using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Felbot.Interaction;
using Felbot.Interface.Conversations;
using Felbot.Interface.Users;
using Felbot.Profiles;
using MBNCSUtil;
using MBNCSUtil.Data;
using MBNCSUtil.Net;

namespace Felbot.Protocol {
    /// <summary>Controls connection to Battle.net.</summary>
    public class BattleNetPacketThread : PacketThread {
        #region Fields and Delegates
        /// <summary>Timer that sends SID_NULL packets regularly.</summary>
        private Timer m_SendNullTimer;

        /// <summary>List of messages in bot queue.</summary>
        private LinkedList<string> m_MessageQueue = new LinkedList<string>();
        /// <summary>Integer used in queue output.</summary>
        private int m_MessageQueueSeconds = 0;
        /// <summary>Timer used in queue output.</summary>
        private Timer m_MessageQueueTimer;

        private bool m_ChatClient = false;
        private bool m_InChat = false;
        private bool m_ConnectionMade = false;
        private string m_UniqueUsername;
        private string m_Namespace = "Offline";
        private string m_LastWhisperSent = null;
        private string m_LastWhisperRecieved = null;
        private const int m_ClientToken = 0x003713FB; // shows as FB 13 37 in packet logs, ;)

        private string m_VersionDll;
        private long m_MpqFiletime;
        private int m_LogonType;
        private int m_UdpValue;
        private int m_ServerToken;
        private byte[] m_VersionFormula;
        private NLS m_Nls;
        private BattleNetClient m_Client;
        private string m_Username = null;
        private string m_Password = null;
        private string m_Cdkey = null;

        private WardenModule m_Warden;

        // private BattleNetRealmPacketThread m_RealmPacketThread;
        private string m_Realm;

        // This is used for various delegate invocations
        private delegate void AnonymousDelegate();

        // This is used to create anonymous methods for timer callbacks.
        private delegate void TimerCallbackDelegate(Object stateInfo);
        #endregion

        #region Super Constructor Thing
        /// <summary>
        /// This will construct a BattleNetPacketThread
        /// </summary>
        /// <param name="main">Instance of frmProfile that message will be printed on</param>
        public BattleNetPacketThread(frmProfile main)
            : base(main) {
            // Create the timer to send SID_NULLs
            m_SendNullTimer = new Timer(new TimerCallback((TimerCallbackDelegate) delegate(Object stateInfo) {
                #region Socket Activity Checking Delegate
                if (m_Socket != null && m_Socket.Connected && m_Connected) {
                    Send_SID_NULL();
                }
                #endregion
            }), null, 0, 300000);

            // Create the state moniting timer.
            m_SocketStateMonitorTimer = new Timer(new TimerCallback((TimerCallbackDelegate) delegate(Object stateInfo) {
                #region Socket State Checking Delegate
                if (m_Socket != null && m_Socket.Connected != m_SocketConnected) {
                    m_SocketConnected = m_Socket.Connected;
                    if (m_Socket.Connected == true) {
                        if (m_frmProfile.Profile.GetSetting("AdvConn", "ProxyUse").ToBoolean(false)) {
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[PROXY] Connected!"));
                        } else {
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] Connected!"));
                        }
                        Socket_Connected();
                    } else {
                        if (m_frmProfile.Profile.GetSetting("AdvConn", "ProxyUse").ToBoolean(false)) {
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[PROXY] Disconnected!"));
                        } else {
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] Disconnected!"));
                        }
                        Socket_Disconnect();
                    }
                }
                #endregion
            }), null, 0, 100);

            // Create the socket reading thread.
            /// <summary>
            /// This function will be constantly looping for the duration of the existance
            /// of an instance of this class, forked to the background in another Thread.
            /// This will handle all the reading of the socket.
            /// </summary>
            m_SocketReader = new Thread(new ThreadStart((AnonymousDelegate) delegate()
            {
                #region Socket Reader Thread
                byte[] header = new byte[4];
                short length;
                byte id;
                byte[] data;
                byte[] chatMessage = new byte[512];
                while (true) {
                    Thread.Sleep(10);
                    if (m_Socket != null && m_Socket.Connected == true) {
                        if (m_Socket.Available > 0) {
                            try {
                                #region Proxy Packet
                                base.Proxy();
                                #endregion

                                #region BNET Packet
                                if (m_Socket.Available >= 4) {
                                    m_Socket.Receive(header, 0, 4, SocketFlags.Peek);

                                    if (header[0] == 0xFF) {
                                        id = header[1];
                                        length = (short) BitConverter.ToUInt16(header, 2);
                                        data = new byte[length];
                                        if (m_Socket.Available >= length) {
                                            m_Socket.Receive(data, 0, length, SocketFlags.None);
                                            if (Program.MainForm.ShowPackets) {
                                                m_frmProfile.RichTextBox.AddTextNodes(
                                                    new TextNode(
                                                        new Font(new FontFamily("Lucida Console"), 12, FontStyle.Regular, GraphicsUnit.Point),
                                                        Color.DodgerBlue,
                                                        "[BNET] RECIEVED PACKET 0x" + id.ToString("X") + " " + ((BattleNetPacketIDs) id).ToString() + ":" + Environment.NewLine +
                                                        DataFormatter.Format(data)
                                                    )
                                                );
                                            }
                                            ParsePacket((DataReader) new BncsReader(data));
                                        }
                                    } else {
                                        #region CHAT
                                        StringBuilder builder = new StringBuilder();
                                        length = (short) m_Socket.Available;
                                        chatMessage = new byte[length];
                                        m_Socket.Receive(chatMessage, 0, length, SocketFlags.None);
                                        builder.Append(new BinaryReader(new MemoryStream(chatMessage)).ReadChars(length));
                                        string messages = builder.ToString();
                                        foreach (string message in messages.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) {
                                            ParseChatPacket(message, chatMessage);
                                        }
                                        #endregion
                                    }
                                }
                                #endregion
                            } catch (SocketException) { }
                        }
                    }
                }
                #endregion
            }));
            m_SocketReader.IsBackground = true;
            m_SocketReader.Start();
        }
        #endregion

        #region Parse/Distributer
        /// <summary>
        /// This is called by ReadSocket when a new packet is received.
        /// </summary>
        /// <param name="a_bPacketId">Packet ID</param>
        /// <param name="a_prReader">An instance of DataReader containg
        /// the packet's data</param>
        protected override void ParsePacket(DataReader dataReader) {
            m_ConnectionMade = true;
            BncsReader reader = (BncsReader) dataReader;
            switch ((BattleNetPacketIDs) reader.PacketID) {
                #region Super Switch Statement...
                case BattleNetPacketIDs.SID_NULL:
                    Recieve_SID_NULL();
                    break;

                case BattleNetPacketIDs.SID_CLIENTID:
                    // unnessisary to parse
                    // (DWORD) Registration Version
                    // (DWORD) Registration Authority
                    // (DWORD) Account Number
                    // (DWORD) Registration Token
                    break;

                case BattleNetPacketIDs.SID_STARTVERSIONING:
                    Recieve_SID_STARTVERSIONING(reader.ReadInt64(), reader.ReadCString(),
                                                reader.ReadNullTerminatedByteArray());
                    break;

                case BattleNetPacketIDs.SID_REPORTVERSION:
                    Recieve_SID_REPORTVERSION(reader.ReadInt32(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_ENTERCHAT:
                    Recieve_SID_ENTERCHAT(reader.ReadCString(), reader.ReadCString(Encoding.UTF7));
                    break;

                case BattleNetPacketIDs.SID_GETCHANNELLIST:
                    List<string> channels = new List<string>();
                    string channelName = reader.ReadCString();
                    do {
                        channels.Add(channelName);
                        channelName = reader.ReadCString();
                    } while (!channelName.Equals(""));
                    Recieve_SID_GETCHANNELLIST(channels);
                    break;

                case BattleNetPacketIDs.SID_CHATEVENT:
                    int eventID = reader.ReadInt32();
                    int[] data = reader.ReadInt32Array(2);
                    reader.Seek(12);
                    string user = reader.ReadCString(Encoding.UTF8);
                    string text;
                    switch (eventID) {
                        case 1:
                        case 2:
                        case 9:
                            text = reader.ReadCString(Encoding.UTF7); //statstring
                            break;
                        default:
                            text = reader.ReadCString(Encoding.UTF8); //other
                            break;
                    }
                    Recieve_SID_CHATEVENT(eventID, data[0], data[1], user, text);
                    break;

                case BattleNetPacketIDs.SID_FLOODDETECTED:
                    Recieve_SID_FLOODDETECTED();
                    break;

                case BattleNetPacketIDs.SID_MESSAGEBOX:
                    Recieve_SID_MESSAGEBOX(reader.ReadInt32(), reader.ReadCString(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_LOGONCHALLENGEEX:
                    Recieve_SID_LOGONCHALLENGEEX(reader.ReadInt32(), reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_PING:
                    Recieve_SID_PING(reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_LOGONCHALLENGE:
                    Recieve_SID_LOGONCHALLENGE(reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_LOGONRESPONSE:
                    Recieve_SID_LOGONRESPONSE(reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_CDKEY:
                    Recieve_SID_CDKEY(reader.ReadInt32(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CHANGEPASSWORD:
                    Recieve_SID_CHANGEPASSWORD(reader.ReadBoolean());
                    break;

                case BattleNetPacketIDs.SID_CDKEY2:
                    Recieve_SID_CDKEY2(reader.ReadInt32(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_LOGONRESPONSE2:
                    Recieve_SID_LOGONRESPONSE2(reader.ReadInt32(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CREATEACCOUNT2:
                    Recieve_SID_CREATEACCOUNT2(reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_LOGONREALMEX:
                    if (reader.Length == 12)
                        Recieve_SID_LOGONREALMEX(reader.ReadInt32(), reader.ReadUInt32());
                    else
                        Recieve_SID_LOGONREALMEX(reader.ReadInt32(), reader.ReadUInt32(), reader.ReadInt32Array(2),
                                                 reader.ReadByteArray(4), reader.ReadInt32(), reader.ReadInt32Array(12),
                                                 reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_QUERYREALMS2:
                    List<string> realms = new List<string>();
                    reader.Seek(4);
                    int count = reader.ReadInt32();
                    for (int i = 0; i < count; i++) {
                        reader.Seek(4);
                        realms.Add(reader.ReadCString() + " (" + reader.ReadCString() + ")");
                    }
                    Recieve_SID_QUERYREALMS2(realms);
                    break;

                case BattleNetPacketIDs.SID_NEWS_INFO:
                    int newsLength = (int) reader.ReadByte();
                    DateTime lastLogin = new DateTime(reader.ReadInt32());
                    reader.Seek(8);
                    Dictionary<DateTime, string> news = new Dictionary<DateTime, string>(newsLength);
                    for (int i = 0; i < newsLength; i++)
                        news.Add(new DateTime(reader.ReadInt32()), reader.ReadCString());
                    Recieve_SID_NEWS_INFO(lastLogin, news);
                    break;

                case BattleNetPacketIDs.SID_AUTH_INFO:
                    Recieve_SID_AUTH_INFO(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32(),
                                          reader.ReadInt64(), reader.ReadCString(), reader.ReadNullTerminatedByteArray());
                    break;

                case BattleNetPacketIDs.SID_AUTH_CHECK:
                    Recieve_SID_AUTH_CHECK(reader.ReadInt32(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTCREATE:
                    Recieve_SID_AUTH_ACCOUNTCREATE(reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTLOGON:
                    Recieve_SID_AUTH_ACCOUNTLOGON(reader.ReadInt32(), reader.ReadByteArray(32), reader.ReadByteArray(32));
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTLOGONPROOF:
                    Recieve_SID_AUTH_ACCOUNTLOGONPROOF(reader.ReadInt32(), reader.ReadByteArray(20), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTCHANGE:
                    Recieve_SID_AUTH_ACCOUNTCHANGE(reader.ReadInt32(), reader.ReadByteArray(32), reader.ReadByteArray(32));
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTCHANGEPROOF:
                    Recieve_SID_AUTH_ACCOUNTCHANGEPROOF(reader.ReadInt32(), reader.ReadByteArray(20));
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTUPGRADE:
                    Recieve_SID_AUTH_ACCOUNTUPGRADE(reader.ReadInt32(), reader.ReadInt32());
                    break;

                case BattleNetPacketIDs.SID_AUTH_ACCOUNTUPGRADEPROOF:
                    Recieve_SID_AUTH_ACCOUNTUPGRADEPROOF(reader.ReadInt32(), reader.ReadByteArray(20));
                    break;

                case BattleNetPacketIDs.SID_SETEMAIL:
                    Recieve_SID_SETEMAIL();
                    break;

                case BattleNetPacketIDs.SID_WARDEN:
                    Recieve_SID_WARDEN(reader.ReadByteArray(reader.Length - 4));
                    break;

                case BattleNetPacketIDs.SID_FRIENDSLIST:
                    List<object[]> friends = new List<object[]>();
                    int count2 = reader.ReadByte();
                    for (int i = 0; i < count2; i++)
                        friends.Add(new object[] { reader.ReadCString(), reader.ReadByte(), reader.ReadByte(), reader.ReadDwordString(0x00), reader.ReadCString() });
                    Recieve_SID_FRIENDSLIST(friends);
                    break;

                case BattleNetPacketIDs.SID_FRIENDSUPDATE:
                    Recieve_SID_FRIENDSUPDATE(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadDwordString(0x00), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_FRIENDSADD:
                    Recieve_SID_FRIENDSADD(reader.ReadCString(), reader.ReadByte(), reader.ReadByte(), reader.ReadDwordString(0x00), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_FRIENDSREMOVE:
                    Recieve_SID_FRIENDSREMOVE(reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_FRIENDSPOSITION:
                    Recieve_SID_FRIENDSPOSITION(reader.ReadByte(), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANFINDCANDIDATES:
                    Recieve_SID_CLANFINDCANDIDATES(reader);
                    break;

                case BattleNetPacketIDs.SID_CLANINVITEMULTIPLE:
                    Recieve_SID_CLANINVITEMULTIPLE(reader);
                    break;

                case BattleNetPacketIDs.SID_CLANCREATIONINVITATION:
                    Recieve_SID_CLANCREATIONINVITATION(reader);
                    break;

                case BattleNetPacketIDs.SID_CLANDISBAND:
                    Recieve_SID_CLANDISBAND(reader.ReadInt32(), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANMAKECHIEFTAIN:
                    Recieve_SID_CLANMAKECHIEFTAIN(reader.ReadInt32(), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANINFO:
                    reader.Seek(1);
                    Recieve_SID_CLANINFO(reader.ReadDwordString(0x00), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANQUITNOTIFY:
                    Recieve_SID_CLANQUITNOTIFY(reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANINVITATION:
                    Recieve_SID_CLANINVITATION(reader.ReadInt32(), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANREMOVEMEMBER:
                    Recieve_SID_CLANREMOVEMEMBER(reader.ReadInt32(), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANINVITATIONRESPONSE:
                    Recieve_SID_CLANINVITATIONRESPONSE(reader.ReadInt32(), reader.ReadDwordString(0x00), reader.ReadCString(),
                                                       reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CLANRANKCHANGE:
                    Recieve_SID_CLANRANKCHANGE(reader.ReadInt32(), reader.ReadByte());
                    break;

                case BattleNetPacketIDs.SID_CLANMOTD:
                    Recieve_SID_CLANMOTD(reader.ReadInt32(), reader.ReadInt32(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CLANMEMBERLIST:
                    Recieve_SID_CLANMEMBERLIST(reader);
                    break;

                case BattleNetPacketIDs.SID_CLANMEMBERREMOVED:
                    Recieve_SID_CLANMEMBERREMOVED(reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CLANMEMBERSTATUSCHANGE:
                    Recieve_SID_CLANMEMBERSTATUSCHANGE(reader.ReadCString(), reader.ReadByte(), reader.ReadByte(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CLANMEMBERRANKCHANGE:
                    Recieve_SID_CLANMEMBERRANKCHANGE(reader.ReadByte(), reader.ReadByte(), reader.ReadCString());
                    break;

                case BattleNetPacketIDs.SID_CLANMEMBERINFORMATION:
                    Recieve_SID_CLANMEMBERINFORMATION(reader.ReadInt32(), reader.ReadByte(), reader.ReadCString(), reader.ReadByte(), DateTime.FromFileTime(reader.ReadInt64()));
                    break;

                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Red, "Unhandled packet received! 0x" + reader.PacketID.ToString("X")));
                    break;
                #endregion
            }
        }
        #endregion

        #region Recieve Packets
        #region 0x00 Handle SID_NULL
        private void Recieve_SID_NULL() {
            Send_SID_NULL();
        }
        #endregion

        #region 0x06 Handle SID_FLOODDETECTED
        private void Recieve_SID_STARTVERSIONING(long mpqFileName, string versionDll, byte[] versionFormula) {
            string product = m_Client.ProductID;
            byte verbyte = m_Client.Verbyte;
            Send_SID_REPORTVERSION(product, verbyte, mpqFileName, versionDll, versionFormula);
        }
        #endregion

        #region 0x07 Handle SID_REPORTVERSION
        private void Recieve_SID_REPORTVERSION(int result, string extraInfo) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Game version is invalid!"));
                    Socket_Disconnect();
                    return;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Game version is outdated! Patch file: " + extraInfo));
                    Socket_Disconnect();
                    patchHashes(extraInfo);
                    return;
                case 0x02:
                    break;
                case 0x03:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Game should be re-installed!"));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Authorization challenge resulted in an unknown code: 0x"
                        + result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            if (m_Client.Equals("JSTR")) {
                Send_SID_CDKEY();
            } else if (m_Client.Equals("W2BN")) {
                Send_SID_CDKEY2();
            } else {    //shareware/drtl
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
                Send_SID_LOGONRESPONSE();
            }
        }
        #endregion

        #region 0x0A Handle SID_ENTERCHAT
        private void Recieve_SID_ENTERCHAT(string uniqueUsername, string stats) {
            m_frmProfile.Clan.EnterChat();
            if (Client.Equals("D2DV") || Client.Equals("D2XP"))
                uniqueUsername = "*" + uniqueUsername;
            m_UniqueUsername = uniqueUsername;
            m_ReconnectAttempts = 0;
            m_frmProfile.Channel.OnEnterChat(uniqueUsername, stats);
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] Entered chat environment as " + uniqueUsername + " using " + new UserStats(stats).ParsedStatString + "!"));
            Send_SID_CHATCOMMAND("/whoami");
            Send_SID_FRIENDSLIST();

            #region Join home channel
            string homeChannel;
            switch (ProfileControl.Global.GetSetting("Automation", "ConnectionWhenConnected").ToInteger(0)) {
                default:
                case 0: //join profile home
                    Send_SID_JOINCHANNEL(true, false, null);

                    homeChannel = m_frmProfile.Profile.GetSetting("Channel", "Home").ToString("");
                    if (!homeChannel.Equals("") && !homeChannel.Equals(m_frmProfile.Channel.ChannelName))
                        Send_SID_JOINCHANNEL(false, false, homeChannel);
                    break;
                case 1: //join setting channel
                    Send_SID_JOINCHANNEL(true, false, null);

                    homeChannel = ProfileControl.Global.GetSetting("Automation", "ConnectionWhenConnectedChannel").ToString("");
                    if (!homeChannel.Equals("") && !homeChannel.Equals(m_frmProfile.Channel.ChannelName))
                        Send_SID_JOINCHANNEL(false, false, homeChannel);
                    break;
                case 2: //join product specific home
                    Send_SID_JOINCHANNEL(true, false, null);
                    break;
                case 3: //stay out of chat environment
                    break;
            }

            if ((Client.Equals("D2DV") || Client.Equals("D2XP") ||
                 Client.Equals("WAR3") || Client.Equals("W3XP")) &&
                ProfileControl.Global.GetSetting("Automation", "WhenConnectedShowNews").ToBoolean(false))
                Send_SID_NEWS_INFO();
            #endregion

            #region Leagues!
            if (Client.Equals("STAR") || Client.Equals("SEXP")) {
                //string m_sLeaguePath = m_frmProfile.Profile.GetSetting("AdvConn", "Hashes").ToString("\\Hashes\\") + "Leagues\";
                //if (Directory.Exists(m_sLeaguePath))
                //MpqServices.OpenArchive(
            }
            #endregion
        }
        #endregion

        #region 0x0B Handle SID_GETCHANNELLIST
        private void Recieve_SID_GETCHANNELLIST(List<string> channels) {
            foreach (string channel in channels)
                m_frmProfile.AddPublicChannel(channel);
        }
        #endregion

        #region 0x0F Handle SID_CHATEVENT
        private void Recieve_SID_CHATEVENT(int id, int flags, int ping, string username, string text) {
            switch ((BattleNetEventIDs) id) {
                #region 0x01 EID_SHOWUSER
                case BattleNetEventIDs.EID_SHOWUSER:
                    m_frmProfile.Channel.OnShowUser(username, text, flags, ping);
                    break;
                #endregion
                #region 0x02 EID_JOIN
                case BattleNetEventIDs.EID_JOIN:
                    m_frmProfile.Channel.OnJoin(username, text, flags, ping);
                    break;
                #endregion
                #region 0x03 EID_LEAVE
                case BattleNetEventIDs.EID_LEAVE:
                    m_frmProfile.Channel.OnLeave(username);
                    break;
                #endregion
                #region 0x04 EID_WHISPER
                case BattleNetEventIDs.EID_WHISPER:
                    m_LastWhisperRecieved = username;
                    m_frmProfile.Channel.OnWhisper(username, text);
                    break;
                #endregion
                #region 0x05 EID_TALK
                case BattleNetEventIDs.EID_TALK:
                    m_frmProfile.Channel.OnTalk(username, text);
                    break;
                #endregion
                #region 0x06 EID_BROADCAST
                case BattleNetEventIDs.EID_BROADCAST:
                    if (username == "")
                        m_frmProfile.Channel.OnBroadcast(username);
                    else
                        m_frmProfile.Channel.OnBroadcast(username, text);
                    break;
                #endregion
                #region 0x07 EID_CHANNEL
                case BattleNetEventIDs.EID_CHANNEL:
                    m_frmProfile.Channel.OnChannel(text, (byte) flags);
                    break;
                #endregion
                #region 0x09 EID_USERFLAGS
                case BattleNetEventIDs.EID_USERFLAGS:
                    m_frmProfile.Channel.OnUserFlags(username, text, flags, ping);
                    break;
                #endregion
                #region 0x0A EID_WHISPERSENT
                case BattleNetEventIDs.EID_WHISPERSENT:
                    m_LastWhisperSent = username;
                    m_frmProfile.Channel.OnWhisperSent(username, text);
                    break;
                #endregion
                #region 0x0D EID_CHANNELFULL
                case BattleNetEventIDs.EID_CHANNELFULL:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Red, "That channel is full."));
                    break;
                #endregion
                #region 0x0E EID_CHANNELDOESNOTEXIST
                case BattleNetEventIDs.EID_CHANNELDOESNOTEXIST:
                    if (text == "NONEXISTANT~CHN")
                        break;
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Red, "That channel does not exist."));
                    break;
                #endregion
                #region 0x0D EID_CHANNELRESTRICTED
                case BattleNetEventIDs.EID_CHANNELRESTRICTED:
                    if (text == "NONEXISTANT~CHN")
                        break;
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Red, "That channel is restricted."));
                    break;
                #endregion
                #region 0x12 EID_INFO
                case BattleNetEventIDs.EID_INFO:
                    if (!m_InChat && text.StartsWith("You are ")) {
                        m_Namespace = text.Substring(text.IndexOf(" in ") + 4);

                        m_InChat = true;
                    } else {
                        m_frmProfile.Channel.OnInfo(text);
                    }
                    break;
                #endregion
                #region 0x13 EID_ERROR
                case BattleNetEventIDs.EID_ERROR:
                    m_frmProfile.Channel.OnError(text);
                    break;
                #endregion
                #region 0x17 EID_EMOTE
                case BattleNetEventIDs.EID_EMOTE:
                    m_frmProfile.Channel.OnEmote(username, text);
                    break;
                #endregion
                #region Default
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Red, "[BNET] An unhandled event has occured, code 0x"
                        + id.ToString("X")));
                    break;
                #endregion
            }
        }
        #endregion

        #region 0x13 Handle SID_FLOODDETECTED
        private void Recieve_SID_FLOODDETECTED() {
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "You are disconnected for flooding!"));
        }
        #endregion

        #region 0x19 Handle SID_MESSAGEBOX
        private void Recieve_SID_MESSAGEBOX(int style, string text, string caption) {
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Gold, "[" + caption.ToUpper() + "]"));
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.White, text));
        }
        #endregion

        #region 0x1D Handle SID_LOGONCHALLENGEEX
        private void Recieve_SID_LOGONCHALLENGEEX(int udpToken, int serverToken) {
            m_UdpValue = udpToken;
            m_ServerToken = serverToken;
        }
        #endregion

        #region 0x25 Handle SID_PING
        public void Recieve_SID_PING(int value) {
            if (!m_frmProfile.Profile.GetSetting("AdvConn", "SpoofPing").ToBoolean(false))
                Send_SID_PING(value);
        }
        #endregion

        #region 0x28 Handle SID_LOGONCHALLENGE
        private void Recieve_SID_LOGONCHALLENGE(int serverToken) {
            m_ServerToken = serverToken;
        }
        #endregion

        #region 0x29 Handle SID_LOGONRESPONSE
        private void Recieve_SID_LOGONRESPONSE(int result) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Incorrect password."));
                    Socket_Disconnect();
                    return;
                case 0x01:
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account does not exist."));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Attempting to create account.."));
                    Send_SID_CREATEACCOUNT2();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication resulted in an unknown code: 0x" +
                        result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            #region UDP Plug
            if (!m_frmProfile.Profile.GetSetting("AdvConn", "UdpPlug").ToBoolean(false))
                Send_SID_UDPPINGRESPONSE();
            #endregion

            #region Enter Chat
            Send_SID_ENTERCHAT();
            Send_SID_GETCHANNELLIST();
            Send_SID_JOINCHANNEL(false, true, "NONEXISTANT~CHN");
            #endregion
        }
        #endregion

        #region 0x30 Handle SID_CDKEY
        public void Recieve_SID_CDKEY(int result, string extraInfo) {
            #region Result Codes
            switch (result) {
                case 0x01:
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key is invalid!"));
                    Socket_Disconnect();
                    return;
                case 0x03:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key has wrong product value!"));
                    Socket_Disconnect();
                    return;
                case 0x04:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key is banned!"));
                    Socket_Disconnect();
                    return;
                case 0x05:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key is in use! (" + extraInfo + ")"));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. Authentication resulted in an unknown code: 0x"
                        + result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
            Send_SID_LOGONRESPONSE();
        }
        #endregion

        #region 0x31 Handle SID_CHANGEPASSWORD
        private void Recieve_SID_CHANGEPASSWORD(bool success) {
            if (success) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] Password successfully changed!"));
            } else {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Password change failed."));
                Socket_Disconnect();
                return;
            }

            m_frmProfile.Profile.SetSetting("Connection", "Password", m_frmProfile.Profile.GetSetting("AdvConn", "ChangePasswordTo").ToString(""));
            m_frmProfile.Profile.SetSetting("AdvConn", "ChangePassword", false);
            m_frmProfile.Profile.SetSetting("AdvConn", "ChangePasswordTo", "");
            m_frmProfile.Profile.SaveSettings();

            Send_SID_LOGONRESPONSE2();
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
        }
        #endregion

        #region 0x36 Handle SID_CDKEY2
        private void Recieve_SID_CDKEY2(int result, string extraInfo) {
            #region Result Codes
            switch (result) {
                case 0x01:
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key is invalid!"));
                    Socket_Disconnect();
                    return;
                case 0x03:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key has wrong product value!"));
                    Socket_Disconnect();
                    return;
                case 0x04:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key is banned!"));
                    Socket_Disconnect();
                    return;
                case 0x05:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. CD-Key is in use! (" + extraInfo + ")"));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] CD-Key authentication failed. Authentication resulted in an unknown code: 0x"
                        + result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
            Send_SID_LOGONRESPONSE();
        }
        #endregion

        #region 0x3A Handle SID_LOGONRESPONSE2
        private void Recieve_SID_LOGONRESPONSE2(int result, string extraInfo) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    break;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account does not exist."));
                    Send_SID_CREATEACCOUNT2();
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Attempting to create account.."));
                    return;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Incorrect password."));
                    Socket_Disconnect();
                    return;
                case 0x06:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account closed. Reason stated:"));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] " + extraInfo));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication resulted in an unknown code: 0x" +
                        result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            #region UDP Plug
            if (!(Client.Equals("D2DV") || Client.Equals("D2XP")))
                if (!m_frmProfile.Profile.GetSetting("AdvConn", "UdpPlug").ToBoolean(false))
                    Send_SID_UDPPINGRESPONSE();
            #endregion

            #region Realm Choice
            if (m_frmProfile.Profile.GetSetting("Connection", "D2Realm").ToBoolean(false)) {
                if (Client.Equals("D2DV") || Client.Equals("D2XP")) {
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] [REALM] Querying realms.."));
                    Send_SID_QUERYREALMS2();
                    return;
                }
            }
            #endregion

            #region Enter Chat
            Send_SID_ENTERCHAT();
            Send_SID_GETCHANNELLIST();
            Send_SID_JOINCHANNEL(false, true, "NONEXISTANT~CHN");
            #endregion
        }
        #endregion

        #region 0x3D Handle SID_CREATEACCOUNT2
        private void Recieve_SID_CREATEACCOUNT2(int result) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] Account created successfully!"));
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains invalid characters."));
                    Socket_Disconnect();
                    return;
                case 0x03:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains an inappropriate word."));
                    Socket_Disconnect();
                    return;
                case 0x04:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. That account already exists."));
                    Socket_Disconnect();
                    return;
                case 0x06:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username was too short."));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. Unknown result code: 0x" + result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion
            Send_SID_LOGONRESPONSE2();

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
        }
        #endregion

        #region 0x3E Handle SID_LOGONREALMEX
        private void Recieve_SID_LOGONREALMEX(int clientToken, uint result, int[] chunk1,
                                              byte[] ipAddress, int portValue, int[] chunk2,
                                              string uniqueUsername) {
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] [REALM] Information recieved. Proceeding to connect to realm."));

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "Realm log-in has been disabled in this build."));
            //m_RealmPacketThread = new BattleNetRealmPacketThread(m_frmProfile, this, m_ClientToken, result, chunk1, chunk2, ipAddress, portValue, uniqueUsername);
            RealmConnected(false);
        }

        private void Recieve_SID_LOGONREALMEX(int clientToken, uint result) {
            switch (result) {
                case 0x80000001:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] [REALM] Realm logon failed. Realm is unavailable."));
                    break;
                case 0x80000002:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] [REALM] Realm logon failed."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] [REALM] Realm logon failed. Response code: " + result.ToString("X")));
                    break;
            }
        }
        #endregion

        #region 0x40 Handle SID_QUERYREALMS2
        private void Recieve_SID_QUERYREALMS2(List<string> realms) {
            if (realms.Count == 0) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] [REALM] Realm logon failed. No realms found."));
                Send_SID_ENTERCHAT();
                Send_SID_GETCHANNELLIST();
                Send_SID_FRIENDSLIST();
                return;
            }

            string availableRealmsList = realms.Count.ToString() + " realm(s) found: ";
            foreach (string realm in realms)
                availableRealmsList += realm + ", ";
            availableRealmsList = availableRealmsList.Substring(0, availableRealmsList.Length - 1) + ".";

            string chosen = realms[0];
            m_Realm = chosen;

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] [REALM] " + availableRealmsList));
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] [REALM] Getting logon information for " + chosen + ".."));

            Send_SID_LOGONREALMEX(chosen);
        }
        #endregion

        #region 0x46 Handle SID_NEWS_INFO
        private void Recieve_SID_NEWS_INFO(DateTime lastLogin, Dictionary<DateTime, string> news) {
            // do something with news data
        }
        #endregion

        #region 0x50 Handle SID_AUTH_INFO
        private void Recieve_SID_AUTH_INFO(int logonType, int serverToken, int udpValue,
                                           long mpqFileTime, string versionDll, byte[] versionFormula) {
            Send_SID_AUTH_CHECK(logonType, serverToken, udpValue,
                                mpqFileTime, versionDll, versionFormula);
        }
        #endregion

        #region 0x51 Handle SID_AUTH_CHECK
        private void Recieve_SID_AUTH_CHECK(int result, string extraInfo) {
            #region Result Codes
            switch (result) {
                case 0x000:
                    break;
                case 0x100:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Game version is outdated! Patch file: " + extraInfo));
                    Socket_Disconnect();
                    patchHashes(extraInfo);
                    return;
                case 0x101:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Game version is invalid!"));
                    Socket_Disconnect();
                    return;
                case 0x102:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Game version should be downgraded! Patch file: " + extraInfo));
                    Socket_Disconnect();
                    return;
                case 0x200:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. CD-Key is invalid!"));
                    Socket_Disconnect();
                    return;
                case 0x201:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. CD-Key is in use! (" + extraInfo + ")"));
                    Socket_Disconnect();
                    return;
                case 0x202:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. CD-Key is banned!"));
                    Socket_Disconnect();
                    return;
                case 0x203:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. CD-Key has wrong product value!"));
                    Socket_Disconnect();
                    return;
                case 0x210:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Expansion CD-Key is invalid!"));
                    Socket_Disconnect();
                    return;
                case 0x211:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Expansion CD-Key is in use! (" + extraInfo + ")"));
                    Socket_Disconnect();
                    return;
                case 0x212:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Expansion CD-Key is banned!"));
                    Socket_Disconnect();
                    return;
                case 0x213:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Expansion CD-Key has wrong product value!"));
                    Socket_Disconnect();
                    return;
                default:
                    if (result > 0x100) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Invalid version code: "
                            + result.ToString("X")));
                    } else {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authorization challenge failed. Authorization challenge resulted in an unknown code: 0x"
                            + result.ToString("X")));
                    }
                    Socket_Disconnect();
                    return;
            }
            #endregion

            #region The Choice
            if (m_frmProfile.Profile.GetSetting("AdvConn", "PasswordChange").ToBoolean(false)) {
                if (Client.Equals("WAR3") || Client.Equals("W3XP"))
                    Send_SID_AUTH_ACCOUNTCHANGE(); //change password w3
                else
                    Send_SID_CHANGEPASSWORD(); //change password w2/sc/d2
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Changing password.."));
            } else {
                if (Client.Equals("W3XP") &&
                    m_frmProfile.Profile.GetSetting("Connection", "TFTtoROCSwitch").ToBoolean(false) &&
                    m_frmProfile.Profile.GetSetting("Connection", "Client").ToString("") == "WAR3") {
                    Send_SID_SWITCHPRODUCT();
                    m_Client = new BattleNetClient("WAR3", m_frmProfile.Profile);
                }
                if (Client.Equals("WAR3") || Client.Equals("W3XP"))
                    Send_SID_AUTH_ACCOUNTLOGON(); //log in w3
                else
                    Send_SID_LOGONRESPONSE2(); //log in sc/d2
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
            }
            #endregion
        }
        #endregion

        #region 0x52 Handle SID_AUTH_ACCOUNTCREATE
        public void Recieve_SID_AUTH_ACCOUNTCREATE(int result) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] Account created successfully!"));
                    break;
                case 0x04:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. That account already exists."));
                    Socket_Disconnect();
                    return;
                case 0x07:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username was too short."));
                    Socket_Disconnect();
                    return;
                case 0x08:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains invalid characters."));
                    Socket_Disconnect();
                    return;
                case 0x09:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains an inappropriate word."));
                    Socket_Disconnect();
                    return;
                case 0x0A:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains too few alphanumeric characters."));
                    Socket_Disconnect();
                    return;
                case 0x0B:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains adjacent punctuation characters."));
                    Socket_Disconnect();
                    return;
                case 0x0C:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. The proposed username contains too many punctuation characters."));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account creation failed. Unknown result code: 0x" + result.ToString("X") + "."));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));

            Send_SID_AUTH_ACCOUNTLOGON();
        }
        #endregion

        #region 0x53 Handle SID_AUTH_ACCOUNTLOGON
        public void Recieve_SID_AUTH_ACCOUNTLOGON(int result, byte[] salt, byte[] serverKey) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    break;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account does not exist!"));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Attempting to create account.."));
                    Send_SID_AUTH_ACCOUNTCREATE();
                    return;
                case 0x05:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account requires upgrade!"));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Attempting to upgrade account.."));
                    Send_SID_AUTH_ACCOUNTUPGRADE();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account logon resulted in an unknown code: 0x"
                        + result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            Send_SID_AUTH_ACCOUNTLOGONPROOF(salt, serverKey);
        }
        #endregion

        #region 0x54 Handle SID_AUTH_ACCOUNTLOGONPROOF
        public void Recieve_SID_AUTH_ACCOUNTLOGONPROOF(int result, byte[] proof, string extraInfo) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    if (!m_Nls.VerifyServerProof(proof)) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Detected server screw-up! Verification of server proof failed, however we can still continue.."));
                    }
                    break;
                case 0x02:
                    if (m_ReconnectAttempts > 0) {
                        m_ReconnectAttempts = 0;
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Incorrect password!"));
                        Socket_Disconnect();
                        return;
                    } else {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Incorrect password! A known server issue could have occured, retrying.. (" + (++m_ReconnectAttempts).ToString() + ")"));
                        Socket_Connect();
                        return;
                    }
                case 0x0E:
                    if (m_frmProfile.Profile.GetSetting("AdvConn", "EmailAddress").ToString("").Length == 0) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] An email address should be registered for this account, however none is set for this profile."));
                    } else {
                        Send_SID_SETEMAIL();
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] An email address should be registered for this account. "), new TextNode(FCSObjects.Chatroom_Bot_Success, "Done!"));
                    }
                    break;
                case 0x0F:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Account closed. Reason stated:"));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] " + extraInfo));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Authentication failed. Authentication resulted in an unknown code: 0x" +
                        result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            #region Enter Chat
            Send_SID_NETGAMEPORT();
            Send_SID_ENTERCHAT();
            Send_SID_GETCHANNELLIST();
            Send_SID_JOINCHANNEL(false, true, "NONEXISTANT~CHN");
            #endregion
        }
        #endregion

        #region 0x55 Handle SID_AUTH_ACCOUNTCHANGE
        public void Recieve_SID_AUTH_ACCOUNTCHANGE(int result, byte[] salt, byte[] serverKey) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    break;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Password change failed. Account does not exist!"));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Attempting to create account.."));
                    Send_SID_AUTH_ACCOUNTCREATE();
                    return;
                case 0x05:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Password change failed. Account requires upgrade!"));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Attempting to upgrade account.."));
                    Send_SID_AUTH_ACCOUNTUPGRADE();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Password change failed. Change resulted in an unknown code: 0x"
                        + result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            Send_SID_AUTH_ACCOUNTCHANGEPROOF(salt, serverKey);
        }
        #endregion

        #region 0x56 Handle SID_AUTH_ACCOUNTCHANGEPROOF
        public void Recieve_SID_AUTH_ACCOUNTCHANGEPROOF(int result, byte[] proof) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    if (!m_Nls.VerifyServerProof(proof)) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Detected server screw-up! Verification of server proof failed, however we can still continue.."));
                    }
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Password change failed. Incorrect old password!"));
                    Socket_Disconnect();
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Password change failed. Change resulted in an unknown code: 0x" +
                        result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            m_frmProfile.Profile.SetSetting("Connection", "Password", m_frmProfile.Profile.GetSetting("AdvConn", "ChangePasswordTo").ToString(""));
            m_frmProfile.Profile.SetSetting("AdvConn", "ChangePassword", false);
            m_frmProfile.Profile.SetSetting("AdvConn", "ChangePasswordTo", "");
            m_frmProfile.Profile.SaveSettings();

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
            Send_SID_AUTH_ACCOUNTLOGON();
        }
        #endregion

        #region 0x57 Handle SID_AUTH_ACCOUNTUPGRADE
        public void Recieve_SID_AUTH_ACCOUNTUPGRADE(int result, int serverToken) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account upgrade failed. Upgrade resulted in an unknown code: 0x" +
                        result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            Send_SID_AUTH_ACCOUNTUPGRADEPROOF(serverToken);
        }
        #endregion

        #region 0x58 Handle SID_AUTH_ACCOUNTUPGRADEPROOF
        public void Recieve_SID_AUTH_ACCOUNTUPGRADEPROOF(int result, byte[] proof) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    if (!m_Nls.VerifyServerProof(proof)) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Detected server screw-up! Verification of server proof failed, however we can still continue.."));
                    }
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[BNET] Account upgrade failed. Upgrade resulted in an unknown code: 0x" +
                        result.ToString("X")));
                    Socket_Disconnect();
                    return;
            }
            #endregion

            Send_SID_AUTH_ACCOUNTLOGON();

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
        }
        #endregion

        #region 0x59 Handle SID_SETEMAIL
        public void Recieve_SID_SETEMAIL() {
            if (m_frmProfile.Profile.GetSetting("AdvConn", "EmailAddress").ToString("").Length == 0) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] An email address should be registered for this account, however none is set for this profile."));
            } else {
                Send_SID_SETEMAIL();
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] An email address should be registered for this account. "), new TextNode(FCSObjects.Chatroom_Bot_Success, "Done!"));
            }
        }
        #endregion

        #region 0x5E Handle SID_WARDEN
        private void Recieve_SID_WARDEN(byte[] data) {
            try {
                string hashPath = Client.HashPath;
                byte[] response = m_Warden.RecieveWarden(data, hashPath);
                if (response != null)
                    Send_SID_WARDEN(response);
            } catch (Exception e) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[WARDEN] Encountered an error:" +
                    Environment.NewLine + e.ToString()));
            }
        }
        #endregion

        #region 0x65 Handle SID_FRIENDSLIST
        private void Recieve_SID_FRIENDSLIST(List<object[]> friends) {
            foreach (object[] friend in friends)
                m_frmProfile.Friends.RecievedFriend(friend[0].ToString(), (byte) friend[1], (byte) friend[2], friend[3].ToString(), friend[4].ToString());
            m_frmProfile.Friends.RecievedFriendList();
        }
        #endregion

        #region 0x66 Handle SID_FRIENDSUPDATE
        private void Recieve_SID_FRIENDSUPDATE(byte position, byte status, byte location,
                                               string product, string locationName) {
            m_frmProfile.Friends.UpdateFriend(position, status, location,
                                                 product, locationName);
        }
        #endregion

        #region 0x67 Handle SID_FRIENDSADD
        private void Recieve_SID_FRIENDSADD(string username, byte status, byte location,
                                            string product, string locationName) {
            m_frmProfile.Friends.AddFriend(username, status, location,
                                              product, locationName);
        }
        #endregion

        #region 0x68 Handle SID_FRIENDSREMOVE
        private void Recieve_SID_FRIENDSREMOVE(byte position) {
            m_frmProfile.Friends.RemoveFriend(position);
        }
        #endregion

        #region 0x69 Handle SID_FRIENDSPOSITION
        private void Recieve_SID_FRIENDSPOSITION(byte oldPosition, byte newPostion) {
            m_frmProfile.Friends.MoveFriend(oldPosition, newPostion);
        }
        #endregion

        #region 0x70 Handle SID_CLANFINDCANDIDATES
        private void Recieve_SID_CLANFINDCANDIDATES(BncsReader reader) {
            int cookie = reader.ReadInt32();
            byte result = reader.ReadByte();
            int count = reader.ReadByte();
            List<string> candidates = new List<string>();
            for (int i = 0; i < count; i++)
                candidates.Add(reader.ReadCString());

            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Found " + candidates.Count + " users for inviting."));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Use the clan tab to check and invite users."));
                    m_frmProfile.Clan.FoundCandidates(cookie, candidates.ToArray());
                    break;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. The clan tag is already in use."));
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. Your account has created a clan too recently."));
                    break;
                case 0x08:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. You are already in a clan."));
                    break;
                case 0x0A:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. Invalid clan tag."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. (0x70: 0x" + candidates + ")"));
                    break;
            }
            #endregion
        }
        #endregion

        #region 0x71 Handle SID_CLANINVITEMULTIPLE
        private void Recieve_SID_CLANINVITEMULTIPLE(BncsReader reader) {
            int cookie = reader.ReadInt32();
            byte result = reader.ReadByte();
            int position = 10;
            int declines = 0;
            string declinerList = "";
            string declinerName;
            bool success = false;

            while (reader.Length > position) {
                declinerName = reader.ReadCString();
                declinerList += declinerName + ", ";
                position += declinerName.Length + 1;
                declines++;
            }
            declinerList = declinerList.Remove(declinerList.Length - 2) + ".";

            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Clan invitations accepted. Clan " + m_frmProfile.Clan.ClanTag + " was successfully created!"));
                    success = true;
                    break;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. The clan tag is already in use."));
                    break;
                case 0x02:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. Your account has created a clan too recently."));
                    break;
                case 0x04:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. The following " + declines.ToString() + " user(s) have declined the invitation: " + declinerList));
                    break;
                case 0x05:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. The following " + declines.ToString() + " user(s) are unavailable: " + declinerList));
                    break;
                case 0x08:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. You are already in a clan."));
                    break;
                case 0x0A:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. Invalid clan tag."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Clan creation failed. (0x71: 0x" + result.ToString("X") + ")"));
                    break;
            }
            #endregion

            m_frmProfile.Clan.InvitedMultiple(success);
        }
        #endregion

        #region 0x72 Handle SID_CLANCREATIONINVITATION
        private void Recieve_SID_CLANCREATIONINVITATION(BncsReader reader) {
            int cookie = reader.ReadInt32(); //cookie
            string tag = reader.ReadDwordString(0x00); //clan tag
            string name = reader.ReadCString(); //clan name
            string inviter = reader.ReadCString(); //inviter's user name
            List<string> invitees = new List<string>();
            for (int i = 0; i < reader.ReadByte(); i++) {
                invitees.Add(reader.ReadCString());
            }
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] You have been invited to create "), new TextNode(Color.Yellow, "Clan " + tag), new TextNode(Color.Cyan, " ("), new TextNode(Color.Yellow, name), new TextNode(Color.Cyan, "). Accept from clan tab."));
            m_frmProfile.Clan.InvitedToClanCreate(cookie, name, tag, inviter, invitees.ToArray());
        }
        #endregion

        #region 0x73 Handle SID_CLANDISBAND
        private void Recieve_SID_CLANDISBAND(int cookie, byte result) {
            #region Result Codes
            switch (result) {
                case 0x00: //successful
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Disbanded clan!"));
                    m_frmProfile.Clan.Disbanded();
                    break;
                case 0x02: //too soon
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Disband failed. You must wait 7 days after clan creation to disband."));
                    break;
                case 0x07: //not authorized
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Disband failed. You must be a Chieftain to disband a clan."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Disband failed. (" + result.ToString("X") + ")"));
                    break;
            }
            #endregion
        }
        #endregion

        #region 0x74 Handle SID_CLANMAKECHIEFTAIN
        private void Recieve_SID_CLANMAKECHIEFTAIN(int cookie, byte result) {
            #region Result Codes
            switch (result) {
                case 0x00: //successful
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Chieftain was changed to " + m_frmProfile.Clan.GetQueueMember("NEWCHIEFTAIN").Username));
                    m_frmProfile.Clan.ChieftainChanged(m_frmProfile.Clan.GetQueueMember("NEWCHIEFTAIN").Username);
                    break;
                case 0x02: //too soon
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Chieftain change failed. You must wait 7 days after clan creation to change Chieftain."));
                    break;
                case 0x04: //declined
                case 0x05: //failed
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Chieftain change failed. Declined."));
                    break;
                case 0x07: //not authorized
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Chieftain change failed. You must be a Chieftain to change Chieftain."));
                    break;
                case 0x08: //not found
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Chieftain change failed. User not found."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Chieftain change failed. (0x74: 0x" + result.ToString("X") + ")"));
                    break;
            }
            #endregion
        }
        #endregion

        #region 0x75 Handle SID_CLANINFO
        private void Recieve_SID_CLANINFO(string tag, byte rank) {
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] You are a "), new TextNode(FCSObjects.Chatroom_Information_Status, m_frmProfile.Clan.GetClanRank(rank)), new TextNode(FCSObjects.Chatroom_Information_Clan, " in clan "), new TextNode(FCSObjects.Chatroom_Information_Status, tag), new TextNode(FCSObjects.Chatroom_Information_Clan, "."));
            m_frmProfile.Clan.RecievedClanInfo(tag);
            Send_SID_CLANMEMBERLIST(ClanQueueMember.GenerateCookie());
            Send_SID_CLANMOTD(ClanQueueMember.GenerateCookie());
            m_frmProfile.Clan.SendClanMemberInformation(ClanQueueMember.GenerateCookie(), tag, m_Username);
        }
        #endregion

        #region 0x76 Handle SID_CLANQUITNOTIFY
        private void Recieve_SID_CLANQUITNOTIFY(byte result) {
            #region Result Codes
            switch (result) {
                case 0x00:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] You have quit the clan."));
                    break;
                case 0x01:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] You were removed from the clan."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] You have quit the clan. (0x76: 0x" + result.ToString("X") + ")"));
                    break;
            }
            #endregion
            m_frmProfile.Clan.Quitted();
        }
        #endregion

        #region 0x77 Handle SID_CLANINVITATION
        public void Recieve_SID_CLANINVITATION(int cookie, byte result) {
            #region Result Codes
            switch (result) {
                case 0x00: //successful/accepted
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] The clan invitation was accepted."));
                    break;
                case 0x04: //declined
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Invitation failed. Declined."));
                    break;
                case 0x05: //failed
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Invitation failed. The user is already in a clan or you are not a Chieftain or Shaman of your clan."));
                    break;
                case 0x09: //not authorized
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Invitation failed. The clan is full."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Invitation failed. (0x77: 0x" + result.ToString("X") + ")"));
                    break;
            }
            #endregion
        }
        #endregion

        #region 0x78 Handle SID_CLANREMOVEMEMBER
        public void Recieve_SID_CLANREMOVEMEMBER(int cookie, byte result) {
            #region Result Codes
            switch (result) {
                case 0x00: //successful/accepted
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] The member was removed."));
                    //Main.ClanList.ClanRemoveMember(Main.ClanList.g_sQueueMember);
                    break;
                case 0x01: //failed
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Removal failed. Unable to remove that member."));
                    break;
                case 0x02: //too soon
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Removal failed. You must wait 7 days after member invitation to remove."));
                    break;
                case 0x07: //not authorized
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Removal failed. You must be a Shaman or a Chieftain to remove a member."));
                    break;
                case 0x08: //not allowed
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Removal failed. You cannot remove that user."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Removal failed. (0x78: 0x" + result.ToString("X") + ")"));
                    break;
            }
            #endregion
        }
        #endregion

        #region 0x79 Handle SID_CLANINVITATIONRESPONSE
        private void Recieve_SID_CLANINVITATIONRESPONSE(int cookie, string tag, string name, string inviter) {
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] You have been invited to join "), new TextNode(Color.Yellow, "Clan " + tag), new TextNode(Color.Cyan, " ("), new TextNode(Color.Yellow, name), new TextNode(Color.Cyan, "). Accept from clan tab."));
            m_frmProfile.Clan.ClanInvitationResponse(cookie, tag, name, inviter);
        }
        #endregion

        #region 0x7A Handle SID_CLANRANKCHANGE
        private void Recieve_SID_CLANRANKCHANGE(int cookie, byte result) {
            #region Result Codes
            switch (result) {
                case 0x00: //successful
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] The member was changed successfully."));
                    break;
                case 0x01: //failed
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Rank change failed. Unable to change that member."));
                    break;
                case 0x02: //too soon
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Rank change failed. You must wait 7 days after member invitation to promote."));
                    break;
                case 0x07: //not authorized
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Rank change failed. You must be a Shaman or a Chieftain to change the rank of a member."));
                    break;
                case 0x08: //not allowed
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Rank change failed. You cannot change the rank of that user."));
                    break;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Rank change failed. (0x7A: 0x" + result.ToString("X") + ")"));
                    break;
            }
            #endregion
        }
        #endregion

        #region 0x7C Handle SID_CLANMOTD
        private void Recieve_SID_CLANMOTD(int cookie, int unknown, string motd) {
            m_frmProfile.Clan.SetClanMotd(motd);
        }
        #endregion

        #region 0x7D Handle SID_CLANMEMBERLIST
        private void Recieve_SID_CLANMEMBERLIST(BncsReader reader) {
            int cookie = reader.ReadInt32();
            int count = reader.ReadByte();
            m_frmProfile.Invoke((AnonymousDelegate) delegate() {
                for (int i = 0; i < count; i++)
                    m_frmProfile.Clan.RecievedClanMember(reader.ReadCString(), reader.ReadByte(), reader.ReadByte(), reader.ReadCString());
                m_frmProfile.Clan.RecievedClanMemberList();
            });
        }
        #endregion

        #region 0x7E Handle SID_CLANMEMBERREMOVED
        private void Recieve_SID_CLANMEMBERREMOVED(string removed) {
            m_frmProfile.Clan.RemoveClanMember(removed);
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] " + removed + " was removed from the clan."));
        }
        #endregion

        #region 0x7F Handle SID_CLANMEMBERSTATUSCHANGE
        private void Recieve_SID_CLANMEMBERSTATUSCHANGE(string name, byte rank, byte status, string location) {
            m_frmProfile.Clan.ChangeClanMemberStatus(name, rank, status, location);
        }
        #endregion

        #region 0x81 Handle SID_CLANMEMBERRANKCHANGE
        private void Recieve_SID_CLANMEMBERRANKCHANGE(byte oldRank, byte newRank, string name) {
            string changeType = "changed";
            m_frmProfile.Clan.ChangeClanMemberRank(oldRank, newRank, name);
            #region Rank Change Type
            switch (oldRank) {
                case 0x00: //peon probation
                    switch (newRank) {
                        case 0x01: //peon
                        case 0x02: //grunt
                        case 0x03: //shaman
                        case 0x04: //chieftain
                            changeType = "promoted";
                            break;
                    }
                    break;
                case 0x01: //peon
                    switch (newRank) {
                        case 0x00: //peon probation
                            changeType = "demoted";
                            break;
                        case 0x02: //grunt
                        case 0x03: //shaman
                        case 0x04: //chieftain
                            changeType = "promoted";
                            break;
                    }
                    break;
                case 0x02: //grunt
                    switch (newRank) {
                        case 0x00: //peon probation
                        case 0x01: //peon
                            changeType = "demoted";
                            break;
                        case 0x03: //shaman
                        case 0x04: //chieftain
                            changeType = "promoted";
                            break;
                    }
                    break;
                case 0x03: //shaman
                    switch (newRank) {
                        case 0x00: //peon probation
                        case 0x01: //peon
                        case 0x02: //grunt
                            changeType = "demoted";
                            break;
                        case 0x04: //chieftain
                            changeType = "promoted";
                            break;
                    }
                    break;
                case 0x04: //chieftain
                    switch (newRank) {
                        case 0x00: //peon probation
                        case 0x01: //peon probation
                        case 0x02: //grunt
                        case 0x03: //shaman
                            changeType = "demoted";
                            break;
                    }
                    break;
            }
            #endregion

            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] " + name + " has " + changeType + " you to a " + m_frmProfile.Clan.GetClanRank(newRank) + "."));
        }
        #endregion

        #region 0x82 Handle SID_CLANMEMBERINFORMATION
        private void Recieve_SID_CLANMEMBERINFORMATION(int cookie, byte result, string clanname, byte rank, DateTime joined) {
            #region Result Codes
            switch (result) {
                case 0x00: //successful
                    break;
                case 0x0C: //user is not in that clan
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] User not found in clan."));
                    return;
                default:
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Error, "[CLAN] Member lookup failed. (0x82: 0x" + result.ToString("X") + ")"));
                    return;
            }
            #endregion
            m_frmProfile.Clan.RecievedClanMemberInformation(cookie, rank, clanname, joined);
        }
        #endregion
        #endregion

        #region Send Packets
        #region 0x00 Send SID_NULL
        ///<summary>Sends 0x00, SID_NULL.</summary>
        private void Send_SID_NULL() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_NULL);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x06 Send SID_LOCALEINFO
        /// <summary>Sends 0x06, SID_LOCALEINFO.</summary>
        /// <param name="a_sProduct">The Product ID.</param>
        /// <param name="a_bVerbyte">The Version Byte.</param>
        private void Send_SID_LOCALEINFO(string product, byte verbyte) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_STARTVERSIONING);
            packet.InsertDwordString("IX86");       // (DWORD) Platform code
            packet.InsertDwordString(product);      // (DWORD) Product code
            packet.InsertInt32((int) verbyte);      // (DWORD) Version code
            packet.InsertInt32(0x00);               // (DWORD) Unknown (0)
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x07 Send SID_REPORTVERSION
        /// <summary>Sends packet 0x07, SID_REPORTVERSION.</summary>
        /// <param name="a_sProduct">The Product ID</param>
        /// <param name="a_bVerbyte">The Version Byte</param>
        /// <param name="a_lMpqFiletime">MPQ Filename</param>
        /// <param name="a_sVersionDLL">Version DLL</param>
        /// <param name="a_bVersionFormula">Version Formula</param>
        private void Send_SID_REPORTVERSION(string product, byte verbyte, long mpqFilename,
                                            string versionDll, byte[] versionFormula) {
            m_MpqFiletime = mpqFilename;
            m_VersionDll = versionDll;
            m_VersionFormula = versionFormula;

            int checksum = -1;
            int versionHash = -1;
            byte[] exeStatstring = null;

            #region Lockdown
            if (!File.Exists(Path.GetTempPath() + m_VersionDll.Replace(".mpq", ".dll"))) {
                //m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Yellow, "[BNET] Downloading and extracting lockdown DLL.."));

                // Download the Lockdown MPQ
                BnFtpVersion1Request bnftpRequest = new BnFtpVersion1Request(Client.ProductID, m_VersionDll, DateTime.FromFileTime(m_MpqFiletime));
                bnftpRequest.LocalFileName = Path.GetTempPath() + m_VersionDll;
                bnftpRequest.ExecuteRequest();

                // Open the MPQ, retreive the file stream for the DLL, and create a output file
                MpqArchive mpq;
                MpqFileStream dll;

                try {
                    mpq = MpqServices.OpenArchive(Path.GetTempPath() + m_VersionDll);
                    dll = mpq.OpenFile(m_VersionDll.Replace(".mpq", ".dll"));
                } catch (TypeInitializationException e) {
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Caught a TypeInitializationException when opening the MPQ: " +
                        Environment.NewLine + e.ToString()));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Inner exception: " + Environment.NewLine +
                        e.InnerException.ToString()));
                    Socket_Disconnect();
                    return;
                }

                FileStream output = File.Create(Path.GetTempPath() + m_VersionDll.Replace("mpq", "dll"));

                // Perform the actual copying
                byte[] data = new byte[dll.Length];
                dll.Read(data, 0, (int) dll.Length);
                output.Write(data, 0, (int) dll.Length);

                // Clean up handles
                output.Close(); output.Dispose();
                dll.Close(); dll.Dispose();
                mpq.Dispose();

                // Delete the MPQ after extracting
                //File.Delete(Path.GetTempPath() + g_sVersionDLL);

                //m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.GreenYellow, "[BNET] Finished! Continuing CheckRevision."));
            }

            exeStatstring = CheckRevision.DoLockdownCheckRevision(m_VersionFormula,
                m_Client.HashFiles,
                Path.GetTempPath() + m_VersionDll.Replace(".mpq", ".dll"),
                m_Client.ImageFile,
                ref versionHash, ref checksum);
            #endregion

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_REPORTVERSION);
            packet.InsertDwordString("IX86");        // (DWORD) Platform code
            packet.InsertDwordString(product);       // (DWORD) Product code
            packet.InsertInt32((int) verbyte);       // (DWORD) Version code
            packet.InsertInt32(versionHash);         // (DWORD) Version hash
            packet.InsertInt32(checksum);            // (DWORD) Version checksum
            packet.InsertByteArray(exeStatstring);   // (String) Version EXE String
            packet.InsertByte(0x00);                 //null terminator
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x0A Send SID_ENTERCHAT
        ///<summary>Sends 0x0A, SID_ENTERCHAT.</summary>
        private void Send_SID_ENTERCHAT() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_ENTERCHAT);
            if (Client.Equals("WAR3") || Client.Equals("W3XP")) {
                packet.InsertByte(0); //nullstring
            } else {
                packet.InsertCString(m_frmProfile.Profile.GetSetting("Connection", "Username").ToString(""));
            }
            packet.InsertByte(0); //nullstring
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x0B Send SID_GETCHANNELLIST
        /// <summary>Sends 0x0B, SID_GETCHANNELLIST.</summary>
        private void Send_SID_GETCHANNELLIST() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_GETCHANNELLIST);
            packet.InsertInt32(0);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x0C Send SID_JOINCHANNEL
        /// <summary>Sends 0x0C, SID_JOINCHANNEL.</summary>
        /// <param name="a_bFirstJoin">When joining the channel for the first time, set to true.</param>
        /// <param name="a_bNoCreateJoin">When trying to join a channel without creating, set to true (ignored if <c>a_bFirstJoin</c> is true).</param>
        /// <param name="a_sChannelName">The channel name (ignored if <c>a_bFirstJoin</c> is true).</param>
        public void Send_SID_JOINCHANNEL(bool firstJoin, bool noCreateJoin, string channelName) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_JOINCHANNEL);
            if (firstJoin) {
                if (Client.Equals("D2DV") || Client.Equals("D2XP")) {
                    packet.InsertInt32(0x05); // first D2
                } else {
                    packet.InsertInt32(0x01); // first normal
                }
                packet.InsertCString("Felbot First Join"); // channel name can't be null =/
            } else {
                if (noCreateJoin) {
                    packet.InsertInt32(0x00); // no create join
                } else {
                    packet.InsertInt32(0x02); // forced join
                }
                packet.InsertCString(channelName); // channel name
            }
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x0E Send SID_CHATCOMMAND
        /// <summary>Sends 0x0E, SID_CHATCOMMAND.</summary>
        /// <param name="a_sMessage">The chat command to say.</param>
        public void Send_SID_CHATCOMMAND(string message) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CHATCOMMAND);
            packet.InsertCString(message, Encoding.UTF8);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x10 Send SID_LEAVECHAT
        /// <summary>Sends 0x10, SID_LEAVECHAT.</summary>
        public void Send_SID_LEAVECHAT() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_LEAVECHAT);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x12 Send SID_LOCALEINFO
        /// <summary>Sends 0x12, SID_LOCALEINFO.</summary>
        private void Send_SID_LOCALEINFO() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_LOCALEINFO);
            packet.InsertInt64(DateTime.Now.ToFileTime());                                  // (FILETIME) System time
            packet.InsertInt64(DateTime.Now.ToFileTime());                                  // (FILETIME) Local time
            packet.InsertInt32((int) DateTime.UtcNow.Subtract(DateTime.Now).TotalMinutes);  // (DWORD)  Timezone Bias
            packet.InsertInt32(CultureInfo.InstalledUICulture.LCID);                        // (DWORD) SystemDefaultLCID
            packet.InsertInt32(CultureInfo.CurrentUICulture.LCID);                          // (DWORD) UserDefaultLCID
            packet.InsertInt32(CultureInfo.CurrentUICulture.LCID);                          // (DWORD) UserDefaultLangID
            packet.InsertCString(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName);    // (STRING) Abbreviated language name
            packet.InsertCString(RegionInfo.CurrentRegion.DisplayName);                     // (STRING) Country name
            packet.InsertCString(RegionInfo.CurrentRegion.ThreeLetterISORegionName);        // (STRING) Abbreviated country name
            packet.InsertCString(CultureInfo.CurrentUICulture.DisplayName);                 // (STRING) Country (English) 
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x14 Send SID_UDPPINGRESPONSE
        /// <summary>Sends 0x14, SID_UDPPINGRESPONSE.</summary>
        private void Send_SID_UDPPINGRESPONSE() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_UDPPINGRESONSE);
            packet.InsertDwordString("bnet");
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x1E Send SID_CLIENTID2
        /// <summary>Sends 0x1E, SID_CLIENTID2.</summary>
        private void Send_SID_CLIENTID2() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLIENTID2);
            packet.InsertInt32(0);                      // (DWORD) Server Version
            packet.InsertInt32(0);                      // (DWORD) Registration Authority
            packet.InsertInt32(0);                      // (DWORD) Registration Version
            packet.InsertInt32(0);                      // (DWORD) Account Number
            packet.InsertInt32(0);                      // (DWORD) Registration Token
            packet.InsertCString("Computer");           // (STRING) LAN computer name
            packet.InsertCString("User");               // (STRING) LAN username 
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x25 Send SID_PING
        /// <summary>Sends 0x25, SID_PING.</summary>
        /// <param name="a_iPing">The ping value.</param>
        private void Send_SID_PING(int pingValue) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_PING);
            packet.InsertInt32(pingValue);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x29 Send SID_LOGONRESPONSE
        /// <summary>Sends 0x29, SID_LOGONRESPONSE.</summary>
        private void Send_SID_LOGONRESPONSE() {
            byte[] hashedPassword = OldAuth.DoubleHashPassword(m_Password, m_ClientToken, m_ServerToken);

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_LOGONRESPONSE);
            packet.InsertInt32(m_ClientToken);
            packet.InsertInt32(m_ServerToken);
            packet.InsertByteArray(hashedPassword);
            packet.InsertCString(m_Username);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x30 Send SID_CDKEY
        /// <summary>Sends 0x30, SID_CDKEY.</summary>
        private void Send_SID_CDKEY() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CDKEY);
            if (m_frmProfile.Profile.GetSetting("Connection", "Spawn").ToBoolean(false)) {
                packet.InsertInt32(0x01);
            } else {
                packet.InsertInt32(0x00);
            }
            packet.InsertCString(m_frmProfile.Profile.GetSetting("Connection", "CdKey").ToString("").Replace("-", "").Trim());
            packet.InsertCString(m_frmProfile.Profile.GetSetting("AdvConn", "KeyOwner").ToString("Felbot"));
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x31 Send SID_CHANGEPASSWORD
        ///<summary>Sends 0x31, SID_CHANGEPASSWORD.</summary>
        private void Send_SID_CHANGEPASSWORD() {
            string newPassword = m_frmProfile.Profile.GetSetting("AdvConn", "ChangePasswordTo").ToString("").ToLower();
            byte[] oldHashedPassword = OldAuth.DoubleHashPassword(m_Password, m_ClientToken, m_ServerToken);
            byte[] newHashedPassword = OldAuth.HashPassword(newPassword);
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_LOGONRESPONSE2);
            packet.InsertInt32(m_ClientToken);
            packet.InsertInt32(m_ServerToken);
            packet.InsertByteArray(oldHashedPassword);
            packet.InsertByteArray(newHashedPassword);
            packet.InsertCString(m_Username);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x36 Send SID_CDKEY2
        /// <summary>Sends 0x36, SID_CDKEY2.</summary>
        private void Send_SID_CDKEY2() {
            string key = m_frmProfile.Profile.GetSetting("Connection", "CdKey").ToString("").Replace("-", "").Trim();
            int length = key.Length;
            CdKey cdKey;
            byte[] cdKeyHash;
            try {
                cdKey = CdKey.CreateDecoder(key);
                cdKeyHash = cdKey.GetHash(m_ClientToken, m_ServerToken);
                if (!cdKey.IsValid) {
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Felbot has detected that CD-key 1 is invalid."));
                }
            } catch (InvalidOperationException e) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Caught invalid operation exception while preparing CD-Key 1: "
                    + Environment.NewLine + e.ToString()));
                Socket_Disconnect();
                return;
            } catch (Exception e) {
                throw e;
            }

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CDKEY2);
            if (m_frmProfile.Profile.GetSetting("Connection", "Spawn").ToBoolean(false)) {
                packet.InsertInt32(0x01);
            } else {
                packet.InsertInt32(0x00);
            }
            packet.InsertInt32(length); //only wc2 will get here, len = 12
            packet.InsertInt32(cdKey.Product);
            packet.InsertInt32(cdKey.Value1);
            packet.InsertInt32(m_ServerToken);
            packet.InsertInt32(m_ClientToken);
            packet.InsertByteArray(cdKeyHash);
            packet.InsertCString(m_frmProfile.Profile.GetSetting("AdvConn", "KeyOwner").ToString("Felbot"));
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x3A Send SID_LOGONRESPONSE2
        ///<summary>Sends 0x3A, SID_LOGONRESPONSE2.</summary>
        private void Send_SID_LOGONRESPONSE2() {
            byte[] hashedPassword = OldAuth.DoubleHashPassword(m_Password, m_ClientToken, m_ServerToken);
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_LOGONRESPONSE2);
            packet.InsertInt32(m_ClientToken);
            packet.InsertInt32(m_ServerToken);
            packet.InsertByteArray(hashedPassword);
            packet.InsertCString(m_Username);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x3D Send SID_CREATEACCOUNT2
        /// <summary>Sends 0x3D, SID_CREATEACCOUNT2.</summary>
        private void Send_SID_CREATEACCOUNT2() {
            byte[] hashedPassword = OldAuth.HashPassword(m_Password);
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CREATEACCOUNT2);
            packet.InsertByteArray(hashedPassword);
            packet.InsertCString(m_Username);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x3E Send SID_LOGONREALMEX
        /// <summary>Sends packet 0x3E, SID_LOGONREALMEX.</summary>
        /// <param name="a_sRealmTitle">The name of the realm we are connecting to.</param>
        private void Send_SID_LOGONREALMEX(string realmTitle) {
            byte[] hashedPassword = OldAuth.DoubleHashPassword("password", m_ClientToken, m_ServerToken);
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_LOGONREALMEX);
            packet.InsertInt32(m_ClientToken);
            packet.InsertByteArray(hashedPassword);
            packet.InsertCString(realmTitle);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x40 Send SID_QUERYREALMS2
        /// <summary>Sends packet 0x40, SID_QUERYREALMS2.</summary>
        private void Send_SID_QUERYREALMS2() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_QUERYREALMS2);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x45 Send SID_NETGAMEPORT
        /// <summary>Sends 0x45, SID_NETGAMEPORT.</summary>
        private void Send_SID_NETGAMEPORT() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_NETGAMEPORT);
            packet.InsertInt16((short) m_frmProfile.Profile.GetSetting("Connection", "Port").ToInteger(6112));
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x46 Send SID_NEWS_INFO
        private void Send_SID_NEWS_INFO() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_NEWS_INFO);
            packet.InsertInt32(0); //get all news
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x50 Send SID_AUTH_INFO
        /// <summary>Sends packet 0x50, SID_AUTH_INFO.</summary>
        /// <param name="a_sProduct">The Product ID.</param>
        /// <param name="a_bVerbyte">The Version Byte.</param>
        private void Send_SID_AUTH_INFO(string product, byte verbyte) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_INFO);
            packet.InsertInt32(0x00);                                                       // (DWORD)  Protocol ID
            packet.InsertDwordString("IX86");                                               // (DWORD)  Platform Code
            packet.InsertDwordString(product);                                              // (DWORD)  Product Code
            packet.InsertInt32((int) verbyte);                                              // (DWORD)  Version Byte
            packet.InsertInt32(CultureInfo.CurrentUICulture.LCID);                          // (DWORD)  Product Language
            packet.InsertInt32(0x0100007F);                                                 // (DWORD)  Local IP
            packet.InsertInt32((int) DateTime.UtcNow.Subtract(DateTime.Now).TotalMinutes);  // (DWORD)  Timezone Bias
            packet.InsertInt32(CultureInfo.CurrentUICulture.LCID);                          // (DWORD)  Locale ID
            packet.InsertInt32(CultureInfo.CurrentUICulture.LCID);                          // (DWORD)  Language ID
            packet.InsertCString(RegionInfo.CurrentRegion.ThreeLetterISORegionName);        // (STRING) Country Abbreviation
            packet.InsertCString(RegionInfo.CurrentRegion.DisplayName);                     // (STRING) Country name
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x51 Send SID_AUTH_CHECK
        /// <summary>Sends 0x51, SID_AUTH_CHECK.</summary>
        /// <param name="a_iLogonType">Logon type.</param>
        /// <param name="a_iServerToken">Server token.</param>
        /// <param name="a_iUdpValue">UDP value.</param>
        /// <param name="a_lMpqFiletime">MPQ Filename.</param>
        /// <param name="a_sVersionDLL">Version DLL.</param>
        /// <param name="a_bVersionFormula">Version Formula.</param>
        private void Send_SID_AUTH_CHECK(int logonType, int serverToken, int udpValue,
                                         long mpqFiletime, string versionDll, byte[] versionFormula) {
            m_LogonType = logonType;
            m_ServerToken = serverToken;
            m_UdpValue = udpValue;
            m_MpqFiletime = mpqFiletime;
            m_VersionDll = versionDll;
            m_VersionFormula = versionFormula;

            #region Hash CD-Key
            int keyCount;
            if (Client.Equals("D2XP") || Client.Equals("W3XP")) {
                keyCount = 2;
            } else {
                keyCount = 1;
            }

            string[] keys = new string[keyCount];
            int[] cdKeyLengths = new int[keyCount];
            CdKey[] cdKeys = new CdKey[keyCount];
            byte[][] cdKeyHashes = new byte[keyCount][];
            keys[0] = m_frmProfile.Profile.GetSetting("Connection", "CdKey").ToString("").Replace("-", "").Trim();
            m_Cdkey = keys[0];
            if (keyCount >= 2) {
                keys[1] = m_frmProfile.Profile.GetSetting("Connection", "ExpCdKey").ToString("").Replace("-", "").Trim();
            }
            for (int i = 0; i < keyCount; i++) {
                try {
                    cdKeyLengths[i] = keys[i].Length;
                    cdKeys[i] = CdKey.CreateDecoder(keys[i]);
                    cdKeyHashes[i] = cdKeys[i].GetHash(m_ClientToken, m_ServerToken);
                    if (!cdKeys[i].IsValid) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Felbot has detected that CD-key " + i.ToString() + " is invalid."));
                        continue;
                    }
                } catch (Exception e) {
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Caught invalid operation exception while preparing CD-Key " + i.ToString() + ": "
                        + Environment.NewLine + e.ToString()));
                    Socket_Disconnect();
                    return;
                }
            }
            #endregion

            #region Perform CheckRevision
            int checksum = -1;
            int versionHash = -1;
            byte[] exeStatbytes = null;
            string exeStatstring = "";
            if (m_Client.Equals("W2BN") || m_Client.Equals("STAR") || m_Client.Equals("SEXP")) {
                #region Lockdown
                if (!File.Exists(Path.GetTempPath() + m_VersionDll.Replace(".mpq", ".dll"))) {
                    //m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Yellow, "[BNET] Downloading and extracting lockdown DLL.."));

                    // Download the Lockdown MPQ
                    BnFtpVersion1Request bnftpRequest = new BnFtpVersion1Request(Client.ProductID, m_VersionDll, DateTime.FromFileTime(m_MpqFiletime));
                    bnftpRequest.LocalFileName = Path.GetTempPath() + m_VersionDll;
                    bnftpRequest.ExecuteRequest();

                    // Open the MPQ, retreive the file stream for the DLL, and create a output file
                    MpqArchive mpq;
                    MpqFileStream dll;

                    try {
                        mpq = MpqServices.OpenArchive(Path.GetTempPath() + m_VersionDll);
                        dll = mpq.OpenFile(m_VersionDll.Replace(".mpq", ".dll"));
                    } catch (TypeInitializationException e) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Caught a TypeInitializationException when opening the MPQ: " +
                            Environment.NewLine + e.ToString()));
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Inner exception: " + Environment.NewLine +
                            e.InnerException.ToString()));
                        Socket_Disconnect();
                        return;
                    }

                    FileStream output = File.Create(Path.GetTempPath() + m_VersionDll.Replace("mpq", "dll"));

                    // Perform the actual copying
                    byte[] data = new byte[dll.Length];
                    dll.Read(data, 0, (int) dll.Length);
                    output.Write(data, 0, (int) dll.Length);

                    // Clean up handles
                    output.Close(); output.Dispose();
                    dll.Close(); dll.Dispose();
                    mpq.Dispose();

                    // Delete the MPQ after extracting
                    //File.Delete(Path.GetTempPath() + g_sVersionDLL);

                    //m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.GreenYellow, "[BNET] Finished! Continuing CheckRevision."));
                }

                exeStatbytes = CheckRevision.DoLockdownCheckRevision(m_VersionFormula,
                    m_Client.HashFiles,
                    Path.GetTempPath() + m_VersionDll.Replace(".mpq", ".dll"),
                    m_Client.ImageFile,
                    ref versionHash, ref checksum);
                #endregion

                #region Prepare for Warden
                if (Client.Equals("STAR") || Client.Equals("SEXP")) {
                    try {
                        m_Warden = new WardenModule(
                            new byte[4] {
                                cdKeyHashes[0][0], cdKeyHashes[0][1],
                                cdKeyHashes[0][2], cdKeyHashes[0][3]
                            });
                    } catch (Exception e) {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[WARDEN] Encountered an error:" +
                            Environment.NewLine + e.ToString()));
                    }
                }
                #endregion
            } else {
                #region IX86Ver
                char[] versionFormulaChars = new char[m_VersionFormula.Length];
                for (int i = 0; i < m_VersionFormula.Length; i++)
                    versionFormulaChars[i] = (char) m_VersionFormula[i];
                checksum = CheckRevision.DoCheckRevision(new String(versionFormulaChars),
                    m_Client.HashFiles,
                    CheckRevision.ExtractMPQNumber(m_VersionDll));

                versionHash = CheckRevision.GetExeInfo(
                    m_Client.HashFiles[0],
                    out exeStatstring);
                #endregion
            }
            #endregion

            #region Send 0x51
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_CHECK);
            packet.InsertInt32(m_ClientToken);
            packet.InsertInt32(versionHash);
            packet.InsertInt32(checksum);
            #region Insert CD-Keys
            packet.InsertInt32(keyCount);
            if (m_frmProfile.Profile.GetSetting("Connection", "Spawn").ToBoolean(false)) {
                packet.InsertInt32(0x01);
            } else {
                packet.InsertInt32(0x00);
            }
            for (int i = 0; i < keyCount; i++) {
                packet.InsertInt32(cdKeyLengths[i]);
                packet.InsertInt32(cdKeys[i].Product);
                packet.InsertInt32(cdKeys[i].Value1);
                packet.InsertInt32(0);
                packet.InsertByteArray(cdKeyHashes[i]);
            }
            #endregion
            if (m_Client.Equals("W2BN") || m_Client.Equals("STAR") || m_Client.Equals("SEXP")) {
                packet.InsertByteArray(exeStatbytes);
                packet.InsertByte(0x00); //null terminator
            } else {
                packet.InsertCString(exeStatstring);
            }
            packet.InsertCString(m_frmProfile.Profile.GetSetting("AdvConn", "KeyOwner").ToString("Felbot"));
            SendPacket(packet.GetData());
            #endregion
        }
        #endregion

        #region 0x52 Send SID_AUTH_ACCOUNTCREATE
        /// <summary>Sends 0x52, SID_AUTH_ACCOUNTCREATE.</summary>
        private void Send_SID_AUTH_ACCOUNTCREATE() {
            string username = m_frmProfile.Profile.GetSetting("Connection", "Username").ToString("");
            byte[] saltAndVerifier = new byte[65 + username.Length];
            m_Nls.CreateAccount(saltAndVerifier, 0, 65 + username.Length);

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTCREATE);
            packet.InsertByteArray(saltAndVerifier);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x53 Send SID_AUTH_ACCOUNTLOGON
        /// <summary>Sends 0x53, SID_AUTH_ACCOUNTLOGON.</summary>
        private void Send_SID_AUTH_ACCOUNTLOGON() {
            m_Nls = new NLS(m_Username, m_Password);
            byte[] a = new byte[33 + m_Username.Length];
            m_Nls.LoginAccount(a, 0, 33 + m_Username.Length);

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTLOGON);
            packet.InsertByteArray(a);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x54 Send SID_AUTH_ACCOUNTLOGONPROOF
        /// <summary>Sends 0x54, SID_AUTH_ACCOUNTLOGONPROOF.</summary>
        /// <param name="a_bSalt">The salt provided in 0x53 S>C SID_AUTH_ACCOUNTLOGON.</param>
        /// <param name="a_bServerKey">The server key provided in 0x53 S>C SID_AUTH_ACCOUNTLOGON.</param>
        private void Send_SID_AUTH_ACCOUNTLOGONPROOF(byte[] salt, byte[] serverKey) {
            byte[] m1 = new byte[20];
            try {
                m_Nls.LoginProof(m1, 0, 20, salt, serverKey);
            } catch (Exception) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] A problem occured when attempting to log you in, trying again.."));
                Socket_Connect();
                return;
            }

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTLOGONPROOF);
            packet.InsertByteArray(m1);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x55 Send SID_AUTH_ACCOUNTCHANGE
        /// <summary>Sends 0x55, SID_AUTH_ACCOUNTCHANGE.</summary>
        private void Send_SID_AUTH_ACCOUNTCHANGE() {
            m_Nls = new NLS(m_Username, m_Password);
            byte[] a = new byte[33 + m_Username.Length];
            m_Nls.LoginAccount(a, 0, 33 + m_Username.Length);

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTCHANGE);
            packet.InsertByteArray(a);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x56 Send SID_AUTH_ACCOUNTCHANGEPROOF
        /// <summary>Sends 0x56, SID_AUTH_ACCOUNTCHANGEPROOF.</summary>
        private void Send_SID_AUTH_ACCOUNTCHANGEPROOF(byte[] salt, byte[] serverKey) {
            string newPassword = m_frmProfile.Profile.GetSetting("AdvConn", "PasswordChangeTo").ToString("").ToLower();

            byte[] m1Old = new byte[20];
            m_Nls.LoginProof(m1Old, 0, 20, salt, serverKey);

            byte[] saltAndVerifierAndName = new byte[65 + m_Username.Length];
            m_Nls = new NLS(m_Username, newPassword);
            byte[] saltAndVerifier = new byte[65 + m_Username.Length];
            m_Nls.CreateAccount(saltAndVerifier, 0, 65 + m_Username.Length);
            byte[] newSaltAndVerifier = new byte[64];
            new MemoryStream(saltAndVerifier).Read(newSaltAndVerifier, 0, 64);

            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTCHANGEPROOF);
            packet.InsertByteArray(m1Old);
            packet.InsertByteArray(newSaltAndVerifier);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x57 Send SID_AUTH_ACCOUNTUPGRADE
        /// <summary>Sends 0x57, SID_AUTH_ACCOUNTUPGRADE.</summary>
        private void Send_SID_AUTH_ACCOUNTUPGRADE() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTUPGRADE);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x58 Send SID_AUTH_ACCOUNTUPGRADEPROOF
        /// <summary>Sends 0x58, SID_AUTH_ACCOUNTUPGRADEPROOF.</summary>
        /// <param name="a_iServerToken">The server token.</param>
        private void Send_SID_AUTH_ACCOUNTUPGRADEPROOF(int serverToken) {
            m_ServerToken = serverToken;
            byte[] oldHashedPassword = OldAuth.DoubleHashPassword(m_Password, m_ClientToken, m_ServerToken);
            m_Nls = new NLS(m_Username, m_Password);
            byte[] saltAndVerifier = new byte[65 + m_Username.Length];
            m_Nls.CreateAccount(saltAndVerifier, 0, 65 + m_Username.Length);
            byte[] newSaltAndVerifier = new byte[64];
            new MemoryStream(saltAndVerifier).Read(newSaltAndVerifier, 0, 64);

            BncsPacket m_pbBncsPacket = new BncsPacket((byte) BattleNetPacketIDs.SID_AUTH_ACCOUNTUPGRADEPROOF);
            m_pbBncsPacket.InsertInt32(m_ClientToken);
            m_pbBncsPacket.InsertByteArray(oldHashedPassword);
            m_pbBncsPacket.InsertByteArray(newSaltAndVerifier);
            SendPacket(m_pbBncsPacket.GetData());
        }
        #endregion

        #region 0x59 Send SID_SETEMAIL
        /// <summary>Sends 0x59, SID_SETEMAIL.</summary>
        private void Send_SID_SETEMAIL() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_SETEMAIL);
            packet.InsertCString(m_frmProfile.Profile.GetSetting("AdvConn", "EmailAddress").ToString());
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x5C Send SID_SWITCHPRODUCT
        /// <summary>Sends 0x5C, SID_SWITCHPRODUCT.</summary>
        private void Send_SID_SWITCHPRODUCT() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_SWITCHPRODUCT);
            packet.InsertDwordString("WAR3");
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x5E Send SID_WARDEN
        /// <summary>Sends 0x5E, SID_WARDEN.</summary>
        /// <param name="a_bEncryptedData">The encrypted packet.</param>
        private void Send_SID_WARDEN(byte[] encryptedData) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_WARDEN);
            packet.InsertByteArray(encryptedData);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x65 Send SID_FRIENDSLIST
        /// <summary>Sends 0x65, SID_FRIENDSLIST.</summary>
        private void Send_SID_FRIENDSLIST() {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_FRIENDSLIST);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x70 Send SID_CLANFINDCANDIDATES
        /// <summary>Sends 0x70, SID_CLANFINDCANDIDATES.</summary>
        /// <param name="m_iCookie">The cookie.</param>
        /// <param name="m_sClanTag">The clan tag.</param>
        public void Send_SID_CLANFINDCANDIDATES(int cookie, string tag) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANFINDCANDIDATES);
            packet.InsertInt32(cookie);
            packet.InsertDwordString(tag);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x71 Send SID_CLANINVITEMULTIPLE
        /// <summary>Sends 0x71, SID_CLANINVITEMULTIPLE.</summary>
        /// <param name="m_iCookie">The cookie.</param>
        /// <param name="m_sClanName">The clan name.</param>
        /// <param name="m_sClanTag">The clan tag.</param>
        /// <param name="m_sInvitees">A string[] of people to invite.</param>
        public void Send_SID_CLANINVITEMULTIPLE(int cookie, string name, string tag, string[] invitees) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANINVITEMULTIPLE);
            packet.InsertInt32(cookie);
            packet.InsertCString(name);
            packet.InsertDwordString(tag);
            packet.InsertByte((byte) invitees.Length);
            for (int i = 0; i < invitees.Length; i++) {
                packet.InsertCString(invitees[i]);
            }
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x72 Send SID_CLANCREATIONINVITATION
        /// <summary>Sends 0x72, SID_CLANCREATIONINVITATION.</summary>
        /// <param name="m_iCookie">The cookie.</param>
        /// <param name="m_sClanTag">The clan tag you are joining.</param>
        /// <param name="m_sInviter">The inviter.</param>
        /// <param name="m_bAccepted">Whether you accepted the invitation.</param>
        public void Send_SID_CLANCREATIONINVITATION(int cookie, string tag, string inviter, bool accepted) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANCREATIONINVITATION);
            packet.InsertInt32(cookie);
            packet.InsertDwordString(tag);
            packet.InsertCString(inviter);
            if (accepted) {
                packet.InsertByte(0x06); //accept
            } else {
                packet.InsertByte(0x04); //decline
            }
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x73 Send SID_CLANDISBAND
        /// <summary>Sends 0x73, SID_CLANDISBAND.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        public void Send_SID_CLANDISBAND(int cookie) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANDISBAND);
            packet.InsertInt32(cookie);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x77 Send SID_CLANINVITATION
        /// <summary>Sends 0x77, SID_CLANINVITATION.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        /// <param name="a_sUsername">The username to invite.</param>
        public void Send_SID_CLANINVITATION(int cookie, string username) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANINVITATION);
            packet.InsertInt32(cookie);
            packet.InsertCString(username);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x78 Send SID_CLANREMOVEMEMBER
        /// <summary>Sends 0x78, SID_CLANREMOVEMEMBER.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        /// <param name="a_sUsername">The username to remove.</param>
        public void Send_SID_CLANREMOVEMEMBER(int cookie, string username) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANREMOVEMEMBER);
            packet.InsertInt32(cookie);
            packet.InsertCString(username);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x79 Send SID_CLANINVITATIONRESPONSE
        /// <summary>Sends 0x79, SID_CLANINVITATIONRESPONSE.</summary>
        /// <param name="m_iCookie">The cookie.</param>
        /// <param name="m_sClanTag">The clan tag you are joining.</param>
        /// <param name="m_sInviter">The inviter.</param>
        /// <param name="m_bAccepted">Whether you accepted the invitation.</param>
        public void Send_SID_CLANINVITATIONRESPONSE(int cookie, string tag, string inviter, bool accepted) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANINVITATIONRESPONSE);
            packet.InsertInt32(cookie);
            packet.InsertDwordString(tag);
            packet.InsertCString(inviter);
            if (accepted) {
                packet.InsertByte(0x06); //accept
            } else {
                packet.InsertByte(0x04); //decline
            }
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x7A Send SID_CLANRANKCHANGE
        /// <summary>Sends 0x7A, SID_CLANRANKCHANGE.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        /// <param name="a_sUsername">The username.</param>
        /// <param name="a_bRank">The new rank.</param>
        public void Send_SID_CLANRANKCHANGE(int cookie, string username, byte rank) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANRANKCHANGE);
            packet.InsertInt32(cookie);
            packet.InsertCString(username);
            packet.InsertByte(rank);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x7B Send SID_CLANSETMOTD
        /// <summary>Sends 0x7B, SID_CLANSETMOTD.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        /// <param name="a_sNewMotd">The MOTD to set it to.</param>
        public void Send_SID_CLANSETMOTD(int cookie, string newMotd) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANSETMOTD);
            packet.InsertInt32(cookie);
            packet.InsertCString(newMotd);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x7C Send SID_CLANMOTD
        /// <summary>Sends 0x7C, SID_CLANMOTD.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        public void Send_SID_CLANMOTD(int cookie) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANMOTD);
            packet.InsertInt32(cookie);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x7D Send SID_CLANMEMBERLIST
        /// <summary>Sends 0x7D, SID_CLANMEMBERLIST.</summary>
        public void Send_SID_CLANMEMBERLIST(int cookie) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANMEMBERLIST);
            packet.InsertInt32(cookie);
            SendPacket(packet.GetData());
        }
        #endregion

        #region 0x82 Send SID_CLANMEMBERINFORMATION
        /// <summary>Sends 0x82, sID_CLANMEMBERINFORMATION.</summary>
        /// <param name="a_iCookie">The cookie.</param>
        /// <param name="a_sClanTag">The clan tag.</param>
        /// <param name="a_sUsername">The username.</param>
        public void Send_SID_CLANMEMBERINFORMATION(int cookie, string tag, string username) {
            BncsPacket packet = new BncsPacket((byte) BattleNetPacketIDs.SID_CLANMEMBERINFORMATION);
            packet.InsertInt32(cookie);
            packet.InsertDwordString(tag);
            packet.InsertCString(username);
            SendPacket(packet.GetData());
        }
        #endregion
        #endregion

        #region CHAT Protocol
        /// <summary>Sends a chat packet terminated by a newline.</summary>
        /// <param name="a_sText">The text to send.</param>
        public void SendChatPacket(string text) {
            DataBuffer chatPacket = new DataBuffer();
            chatPacket.InsertByteArray(Encoding.UTF8.GetBytes(text));
            chatPacket.InsertByte((byte) '\r');
            chatPacket.InsertByte((byte) '\n');
            SendPacket(chatPacket.GetData());
        }

        /// <summary>Parses a chat packet without a newline.</summary>
        private void ParseChatPacket(string message, byte[] buffer) {
            if (!m_ChatClient) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] Unknown data:" + Environment.NewLine + DataFormatter.Format(buffer)));
                return;
            }
            string[] messageSplit = message.Split(" ".ToCharArray(), 3, StringSplitOptions.RemoveEmptyEntries);
            string[] arguments = new string[0];
            if (messageSplit.Length >= 3)
                arguments = messageSplit[2].Split(" ".ToCharArray(), 3, StringSplitOptions.RemoveEmptyEntries);
            int commandNumber = 0;
            try {
                commandNumber = int.Parse(messageSplit[0]);
            } catch (Exception) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Info, "[CHAT] " + message));
                return;
            }
            try {
                string eventText;
                if (arguments.Length >= 3 && !arguments[0].StartsWith("\""))
                    eventText = arguments[2].Trim("[]\"".ToCharArray());
                else
                    eventText = messageSplit[2].Trim("[]\"".ToCharArray());
                switch ((BattleNetEventIDs) (commandNumber - 1000)) //this is a nice find that 1001-1000=0x01, the EID, works for all EIDs.
                {
                    #region 1001 EID_SHOWUSER
                    case BattleNetEventIDs.EID_SHOWUSER: //USER -- ShowUser
                        if (!m_InChat && arguments[0] == m_UniqueUsername) {
                            m_InChat = true;
                            m_frmProfile.Channel.OnEnterChat(m_UniqueUsername, eventText);
                        }
                        m_frmProfile.Channel.OnShowUser(arguments[0], eventText, int.Parse(arguments[1]), 0);
                        break;
                    #endregion
                    #region 1002 EID_JOIN
                    case BattleNetEventIDs.EID_JOIN: //JOIN
                        m_frmProfile.Channel.OnJoin(arguments[0], eventText, int.Parse(arguments[1]), 0);
                        break;
                    #endregion
                    #region 1003 EID_LEAVE
                    case BattleNetEventIDs.EID_LEAVE: //LEAVE
                        m_frmProfile.Channel.OnLeave(arguments[0]);
                        break;
                    #endregion
                    #region 1004 EID_WHISPER
                    case BattleNetEventIDs.EID_WHISPER: //WHISPER -- From
                        m_LastWhisperRecieved = arguments[0];
                        m_frmProfile.Channel.OnWhisper(arguments[0], eventText);
                        break;
                    #endregion
                    #region 1005 EID_TALK
                    case BattleNetEventIDs.EID_TALK: //TALK
                        m_frmProfile.Channel.OnTalk(arguments[0], eventText);
                        break;
                    #endregion
                    #region 1006 EID_BROADCAST
                    case BattleNetEventIDs.EID_BROADCAST: //ADMIN
                        m_frmProfile.Channel.OnBroadcast(eventText);
                        break;
                    #endregion
                    #region 1007 EID_CHANNEL
                    case BattleNetEventIDs.EID_CHANNEL: //CHANNEL
                        m_frmProfile.Channel.OnChannel(eventText, 0x00);
                        break;
                    #endregion
                    #region 1009 EID_USERFLAGS
                    case BattleNetEventIDs.EID_USERFLAGS: //USER -- FlagUpdate
                        m_frmProfile.Channel.OnUserFlags(arguments[0], eventText, int.Parse(arguments[1]), 0);
                        break;
                    #endregion
                    #region 1010 EID_WHISPERSENT
                    case BattleNetEventIDs.EID_WHISPERSENT: //WHISPER -- To
                        m_LastWhisperSent = arguments[0];
                        m_frmProfile.Channel.OnWhisperSent(arguments[0], eventText);
                        break;
                    #endregion
                    #region 1018 EID_INFO
                    case BattleNetEventIDs.EID_INFO: //INFO
                        m_frmProfile.Channel.OnInfo(eventText);
                        break;
                    #endregion
                    #region 1019 EID_ERROR
                    case BattleNetEventIDs.EID_ERROR:
                        m_frmProfile.Channel.OnError(eventText);
                        break;
                    #endregion
                    #region 1023 EID_EMOTE
                    case BattleNetEventIDs.EID_EMOTE: //EMOTE
                        m_frmProfile.Channel.OnEmote(arguments[0], eventText);
                        break;
                    #endregion
                    #region 2000 EID_NULL
                    case BattleNetEventIDs.EID_NULL: //NULL
                        SendChatPacket("");
                        break;
                    #endregion
                    #region 2010 EID_NAME
                    case BattleNetEventIDs.EID_NAME: //NAME
                        m_UniqueUsername = messageSplit[2];
                        m_Namespace = "Chat";
                        m_frmProfile.RichTextBox.AddTextNodes(
                            new TextNode(Color.GreenYellow, "[BNET] Entered chat environment as " + m_UniqueUsername + "!"));
                        #region Join home channel
                        string m_sHomeChannel = m_frmProfile.Profile.GetSetting("Channel", "Home").ToString();
                        if (!m_sHomeChannel.Equals("") && !m_sHomeChannel.Equals(m_frmProfile.Channel.ChannelName) && m_frmProfile.Profile.GetSetting("Channel", "OnLogonJoinHome").ToBoolean(true))
                            SendChatPacket("/join " + m_sHomeChannel);
                        #endregion
                        break;
                    #endregion
                    #region Default
                    default:
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Aqua, "[CHAT] (Unknown Command ID) " + message));
                        break;
                    #endregion
                }
            } catch (Exception) {
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Information_Info, "[CHAT] " + message));
            }
        }
        #endregion
        
        #region Patch Client
        /// <summary>This is used for the patch thread.</summary>
        private delegate void PatcherDelegate();
        /// <summary>This is used for the patch thread.</summary>
        private delegate void PatcherLoadDelegate(object sender, EventArgs e);
        /// <summary>This is used for the patch thread.</summary>
        private delegate void PatcherProgressDelegate(object sender, DownloadStatusEventArgs e);

        /// <summary>
        /// Called to start patching the hashes. Note: this doesn't work yet.
        /// </summary>
        /// <param name="extraInfo">The MPQ name given by Battle.net.</param>
        public void patchHashes(string extraInfo) {
            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Orange, "Automatic patching has been disabled in this build. Please manually patch your client."));
            /*
            using (Form frmPatcher = new Form())
            using (Label patchProgressLabel = new Label())
            using (ProgressBar patchProgressBar = new ProgressBar()) {
                frmPatcher.FormBorderStyle = FormBorderStyle.FixedToolWindow;
                frmPatcher.Text = "Felbot Patcher";
                frmPatcher.Size = new Size(500, 100);
                frmPatcher.TopMost = true;
                frmPatcher.UseWaitCursor = true;
                frmPatcher.ShowInTaskbar = false;
                frmPatcher.StartPosition = FormStartPosition.CenterScreen;

                patchProgressLabel.Text = "Patching " + Client.ProductName + "..";
                patchProgressLabel.AutoSize = true;
                patchProgressLabel.Location = new Point(6, 6);

                patchProgressBar.Style = ProgressBarStyle.Continuous;
                patchProgressBar.Minimum = 0;
                patchProgressBar.Maximum = 120;
                patchProgressBar.Value = 0;
                patchProgressBar.Location = new Point(6, 32);
                patchProgressBar.Size = new Size(465, 30);

                frmPatcher.Controls.Add(patchProgressLabel);
                frmPatcher.Controls.Add(patchProgressBar);

                frmPatcher.Load += new EventHandler((PatcherLoadDelegate) delegate(object sender, EventArgs e) {
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Yellow, "[BNFTP] Patching hash files.."));
                    string filePath = Client.HashPath + extraInfo;
                    BnFtpVersion1Request ftpreq = null;
                    BnFtpVersion2Request ftpreq2 = null;
                    float dec = 0.0f;
                    int percent = 0;

                    PatcherProgressDelegate ppdel = delegate(object sender2, DownloadStatusEventArgs e2) {
                        dec = ((float) e2.DownloadStatus / (float) e2.FileLength);
                        percent = (int) (dec * 100f);
                        patchProgressLabel.Text = "Downloading " + Client.ProductName + " patch MPQ file: " + e2.FileName + " (" + percent.ToString() + "%)..";
                        patchProgressBar.Value = percent;
                    };

                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Yellow, "[BNFTP] Downloading patch MPQ.."));
                    switch (Client.ProductID) {
                        case "STAR":
                        case "SEXP":
                        case "D2DV":
                        case "D2XP":
                        case "W2BN":
                            ftpreq = new BnFtpVersion1Request(Client.ProductID, filePath, DateTime.Now);
                            ftpreq.FilePartDownloaded += new DownloadStatusEventHandler(ppdel);
                            ftpreq.ExecuteRequest();
                            break;

                        case "WAR3":
                        case "W3XP":
                            ftpreq2 = new BnFtpVersion2Request(Client.ProductID, filePath, DateTime.Now, m_Cdkey);
                            ftpreq2.FilePartDownloaded += new DownloadStatusEventHandler(ppdel);
                            ftpreq2.ExecuteRequest();
                            break;

                        default:
                            frmPatcher.Close();
                            return;
                    }
                    patchProgressLabel.Text = "Completing download..";
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Yellow, "[BNFTP] Extracting hash files.."));

                    if (File.Exists(filePath) && new FileInfo(filePath).Extension == ".mpq") {
                        MpqArchive mpqar = MpqServices.OpenArchive(filePath);
                        string internalmpqpath;
                        if (mpqar.ContainsFile("mpqs.lst")) {
                            patchProgressLabel.Text = "Extracting: mpqs.lst..";
                            internalmpqpath = new StreamReader(mpqar.OpenFile("mpqs.lst")).ReadLine().Trim();
                        } else {
                            internalmpqpath = "Patch_" + Client.ProductID + ".mpq";
                        }
                        if (mpqar.ContainsFile(internalmpqpath)) {
                            patchProgressLabel.Text = "Extracting: " + internalmpqpath + "..";
                            MpqFileStream mpqfsmpq = mpqar.OpenFile(internalmpqpath);
                            File.WriteAllBytes(Client.HashPath + internalmpqpath, new BinaryReader(mpqfsmpq).ReadBytes((int) mpqfsmpq.Length));

                            MpqArchive intmpqar = MpqServices.OpenArchive(Client.HashPath + internalmpqpath);

                            foreach (string hash in Client.HashFiles) {
                                if (intmpqar.ContainsFile(hash)) {
                                    patchProgressLabel.Text = "Extracting: " + hash + "..";
                                    MpqFileStream mpqfshash = mpqar.OpenFile(hash);
                                    File.WriteAllBytes(Client.HashPath + hash, new BinaryReader(mpqfshash).ReadBytes((int) mpqfshash.Length));
                                }
                            }
                        } else {
                            MessageBox.Show("Patch failed. Unable to find hash files in MPQ.",
                                            "Felbot",
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Error);
                            frmPatcher.Close();
                            return;
                        }
                        if (mpqar.ContainsFile("patch.txt")) {
                            patchProgressLabel.Text = "Extracting: patch.txt..";
                            File.WriteAllText(Client.HashPath + "patch.txt", new StreamReader(mpqar.OpenFile("patch.txt")).ReadToEnd());
                            if (MessageBox.Show("A patch log file has been extracted. View?",
                                                "Felbot",
                                                MessageBoxButtons.YesNo,
                                                MessageBoxIcon.Error,
                                                MessageBoxDefaultButton.Button1) == DialogResult.Yes) {
                                Process.Start(Client.HashPath + "patch.txt");
                            }
                        }
                    } else {
                        MessageBox.Show("Patch failed. MPQ not downloaded.",
                                        "Felbot",
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                        frmPatcher.Close();
                        return;
                    }

                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.Yellow, "[BNFTP] Incrementing verbyte.."));
                    patchProgressLabel.Text = "Configuring Felbot..";
                    patchProgressBar.Value = 115;

                    m_frmProfile.Profile.SetSetting("AdvConn", "Verbyte", Client.Verbyte + 1);
                    m_Client = new BattleNetClient(Client.ProductID, m_frmProfile.Profile);

                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(Color.GreenYellow, "[BNFTP] Patch complete."));
                    patchProgressLabel.Text = "Complete.";
                    patchProgressBar.Value = 120;

                    if (MessageBox.Show("Patching complete. Reconnect to Battle.net?",
                                        "Felbot",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                                            MessageBoxDefaultButton.Button1) == DialogResult.Yes) {
                        Socket_Connect();
                    }

                    frmPatcher.Close();
                });

                frmPatcher.ShowDialog();
            }
            */
        }
        #endregion

        #region Realms
        /// <summary>
        /// The BAttleNetRealmPacketThread calls this when realm
        /// connection completes so this can continue the connection
        /// sequence.
        /// </summary>
        /// <param name="a_bSucceeded">
        /// If true, the realm connection succeeded and the bot should
        /// be logged into the realm.
        /// </param>
        public void RealmConnected(bool success) {
            if (success)
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "[BNET] [REALM] Realm logon succeeded."));
            else
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] [REALM] Realm logon failed."));
            Send_SID_ENTERCHAT();
            Send_SID_GETCHANNELLIST();
            Send_SID_FRIENDSLIST();
        }
        #endregion

        #region Connection
        /// <summary>
        /// This is a public method to begin connecting the socket.
        /// </summary>
        public override bool Socket_Connect() {
            m_ConnectionMade = false;
            if (!base.Socket_Connect())
                return false;

            #region Connection Sanity
            string m_sClient = m_frmProfile.Profile.GetSetting("Connection", "Client").ToString("");

            if (m_frmProfile.Profile.GetSetting("Connection", "Server").ToString("") == "")
                throw new ArgumentOutOfRangeException(null, "The server setting is empty.");
            if (m_frmProfile.Profile.GetSetting("Connection", "Client").ToString("") == "")
                throw new ArgumentOutOfRangeException(null, "The client setting is empty.");
            if (m_frmProfile.Profile.GetSetting("Connection", "Username").ToString("") == "")
                throw new ArgumentOutOfRangeException(null, "The username setting is empty.");
            if (m_frmProfile.Profile.GetSetting("Connection", "Password").ToString("") == "")
                throw new ArgumentOutOfRangeException(null, "The password setting is empty.");
            if (m_sClient.Equals("JSTR") ||
                m_sClient.Equals("STAR") || m_sClient.Equals("SEXP") ||
                m_sClient.Equals("D2DV") || m_sClient.Equals("D2XP") ||
                m_sClient.Equals("W2BN") ||
                m_sClient.Equals("WAR3") || m_sClient.Equals("W3XP"))
                if (m_frmProfile.Profile.GetSetting("Connection", "CdKey").ToString("") == "")
                    throw new ArgumentOutOfRangeException(null, "The CD-Key setting is empty.");
            if (m_sClient.Equals("D2XP") || m_sClient.Equals("W3XP"))
                if (m_frmProfile.Profile.GetSetting("Connection", "ExpCdKey").ToString("") == "")
                    throw new ArgumentOutOfRangeException(null, "The Expansion CD-Key setting is empty.");
            if (!(m_sClient.Equals("JSTR") || m_sClient.Equals("SSHR") ||
                  m_sClient.Equals("STAR") || m_sClient.Equals("SEXP") ||
                  m_sClient.Equals("DSHR") || m_sClient.Equals("DRTL") ||
                  m_sClient.Equals("D2DV") || m_sClient.Equals("D2XP") ||
                  m_sClient.Equals("W2BN") ||
                  m_sClient.Equals("WAR3") || m_sClient.Equals("W3XP") ||
                  m_sClient.Equals("CHAT")))
                throw new ArgumentOutOfRangeException(null, "You have not selected a valid client. See the readme for more information.");
            #endregion

            m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            new Thread(new ThreadStart(delegate() {
                try {
                    string server;
                    int port;
                    if (m_frmProfile.Profile.GetSetting("AdvConn", "ProxyUse").ToBoolean(false)) {
                        server = m_frmProfile.Profile.GetSetting("AdvConn", "ProxyServer").ToString("");
                        port = m_frmProfile.Profile.GetSetting("AdvConn", "ProxyPort").ToInteger(1080);
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[PROXY] Connecting to " + server + ":" + port + ".."));
                    } else {
                        server = m_frmProfile.Profile.GetSetting("Connection", "Server").ToString("");
                        port = m_frmProfile.Profile.GetSetting("Connection", "Port").ToInteger(6112);
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Connecting to " + server + (port == 6112 ? "" : ":" + port) + ".."));
                    }
                    m_Socket.Connect(server, port);
                } catch (Exception e) {
                    if (e.Message == "An existing connection was forcibly closed by the remote host") {
                        if (m_ConnectionMade) {
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You have lost connection to Battle.net."));
                            Socket_Connect();
                            return;
                        }
                        if (m_ReconnectAttempts > 1) {
                            m_ReconnectAttempts = 0;
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You are IPBanned, or you have lost your internet connection.  Please try connecting later."));
                            Socket_Disconnect();
                            return;
                        } else {
                            m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You have been IPBanned or your connection has been interrupted, reconnecting.. (" + (++m_ReconnectAttempts).ToString() + ")"));
                            Socket_Connect();
                            return;
                        }
                    }
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] Caught exception in Socket_Connect(): " + Environment.NewLine + e.ToString()));
                    return;
                }
            })).Start();
            return true;
        }

        /// <summary>
        /// This is a public method to disconnect the socket.
        /// </summary>
        public override bool Socket_Disconnect() {
            if (base.Socket_Disconnect()) {
                m_InChat = false;
                m_Namespace = "Offline";
                m_LastWhisperSent = null;
                m_LastWhisperRecieved = null;
                m_frmProfile.ClearChannels();
                m_frmProfile.Channel.Disconnect();
                m_frmProfile.Friends.Disconnect();
                m_frmProfile.Clan.Disconnect();
                // if (m_RealmPacketThread != null) {
                //     m_RealmPacketThread.Socket_Disconnect();
                //     m_RealmPacketThread = null;
                // }
                return true;
            }
            return false;
        }

        /// <summary>
        /// This is called when the connect is successful and all proxy-related stuff is complete (or no proxy related stuff is done at all)
        /// </summary>
        internal override void Socket_ConnectedComplete() {
            m_Connected = true;
            m_Client = new BattleNetClient(m_frmProfile.Profile.GetSetting("Connection", "Client").ToString(""), m_frmProfile.Profile);
            if (Client.Equals("WAR3") && m_frmProfile.Profile.GetSetting("Connection", "TFTtoROCSwitch").ToBoolean(false))
                m_Client = new BattleNetClient("W3XP", m_frmProfile.Profile);
            string m_sProduct = m_Client.ProductID;
            byte m_bVerbyte = m_Client.Verbyte;
            m_ChatClient = Client.Equals("CHAT");
            m_Username = m_frmProfile.Profile.GetSetting("Connection", "Username").ToString("");
            m_Password = m_frmProfile.Profile.GetSetting("Connection", "Password").ToString("").ToLower();
            try {
                m_frmProfile.Channel.Connecting();
                m_frmProfile.Clan.Connecting();
            } catch (InvalidOperationException) {   //window is closing
                return;
            }

            if (m_ChatClient) {
                SendByte((byte) BattleNetProtocolBytes.Chat);

                if (!m_Disconnecting) {
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Requesting logon authorization as " + Client.ProductName + ".."));
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Authenticating with logon credentials as " + m_Username + ".."));
                }

                SendChatPacket(m_Username);
                SendChatPacket(m_Password);
            } else {
                SendByte((byte) BattleNetProtocolBytes.Game); // Protocol byte

                if (!m_Disconnecting)
                    m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Try, "[BNET] Requesting logon authorization as " + Client.ProductName + ".."));

                if (Client.Equals("STAR") || Client.Equals("SEXP") ||
                    Client.Equals("D2DV") || Client.Equals("D2XP") ||
                    Client.Equals("WAR3") || Client.Equals("W3XP")) {
                    Send_SID_AUTH_INFO(m_sProduct, m_bVerbyte);
                } else {    //LEGACY TIME!!
                    Send_SID_CLIENTID2();
                    Send_SID_LOCALEINFO();
                    Send_SID_LOCALEINFO(m_sProduct, m_bVerbyte);
                }

                if (m_frmProfile.Profile.GetSetting("AdvConn", "SpoofPing").ToBoolean(false))
                    if (m_frmProfile.Profile.GetSetting("AdvConn", "SpoofPingTo").ToInteger(0) == 0)
                        Send_SID_PING(m_ClientToken);
            }
        }

        /// <summary>
        /// This sends a raw byte across the socket.
        /// </summary>
        /// <param name="a_bData">Data</param>
        internal override void SendByte(byte data) {
            if (m_Disconnecting || !m_Connected)
                return;
            try {
                m_Socket.Send(new byte[] { data });
                if (Program.MainForm.ShowPackets) {
                    m_frmProfile.RichTextBox.AddTextNodes(
                        new TextNode(
                            new Font(new FontFamily("Lucida Console"), 12, FontStyle.Regular, GraphicsUnit.Point),
                            Color.DodgerBlue,
                            "[BNET] SENT BYTE 0x" + data.ToString("X")
                        )
                    );
                }
            } catch (Exception e) {
                if (e.Message == "An existing connection was forcibly closed by the remote host") {
                    if (m_ReconnectAttempts > 1) {
                        m_ReconnectAttempts = 0;
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You are IPBanned, or you have lost your internet connection.  Please try connecting later."));
                        Socket_Disconnect();
                        return;
                    } else {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You have been IPBanned or your connection has been interrupted, reconnecting.. (" + (++m_ReconnectAttempts).ToString() + ")"));
                        Socket_Connect();
                        return;
                    }
                }
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] Caught exception in SendByte(): " + Environment.NewLine + e.ToString()));
            }
        }

        /// <summary>
        /// This sends a packet across the socket.
        /// </summary>
        /// <param name="a_bData">Data</param>
        internal override void SendPacket(byte[] data) {
            if (m_Disconnecting || !m_Connected)
                return;
            try {
                m_Socket.Send(data);
                if (Program.MainForm.ShowPackets) {
                    m_frmProfile.RichTextBox.AddTextNodes(
                        new TextNode(
                            new Font(new FontFamily("Lucida Console"), 12, FontStyle.Regular, GraphicsUnit.Point),
                            Color.DodgerBlue,
                            "[BNET] SENT PACKET 0x" + data[1].ToString("X") + ((BattleNetPacketIDs) data[1]).ToString() + ":" + Environment.NewLine +
                            DataFormatter.Format(data)
                        )
                    );
                }
            } catch (Exception e) {
                if (e.Message == "An existing connection was forcibly closed by the remote host") {
                    if (m_ReconnectAttempts > 1) {
                        m_ReconnectAttempts = 0;
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You are IPBanned, or you have lost your internet connection.  Please try connecting later."));
                        Socket_Disconnect();
                        return;
                    } else {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] You have been IPBanned or your connection has been interrupted, reconnecting.. (" + (++m_ReconnectAttempts).ToString() + ")"));
                        Socket_Connect();
                        return;
                    }
                }
                m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "[BNET] Caught exception in SendPacket(): " + Environment.NewLine + e.ToString()));
            }
        }
        #endregion

        #region Queue and Text
        /// <summary>
        /// This public method is called by frmProfile to send text. If
        /// the queue is enabled, <c>a_sText</c> will get sent to the
        /// queue, and if not, it'll get sent directly to
        /// sendTextBypassQueue.
        /// </summary>
        /// <param name="a_sText"></param>
        public void SendText(string text) {
            if (CommandProcessor.ProcessCommand(new CommandSource(CommandSourcePlace.InBot, null, m_frmProfile.Profile), text)) {
                // command handled internally
            } else {
                AddQueue(text);
            }
        }

        public void AddQueue(string message) {
            if (message.Length == 0) {
                return;
            }
            if (message.Length > 220 && message.Contains(" ")) {
                // If message is too long to display in a single AddQ, split into multiple messages
                string[] messageArray = message.Split(' ');
                string[] queueArray = new string[1024];
                int queueLength = 0;
                string messageTempPart = "";

                for (int i = 0; i < messageArray.Length; i++) {
                    if (messageTempPart.Length + messageArray[i].Length + 1 < 205) {
                        messageTempPart += messageArray[i] + " ";
                    } else {
                        queueArray[queueLength] = messageTempPart + "[more]";
                        queueLength++;
                        messageTempPart = messageArray[i] + " ";
                    }
                }
                queueArray[queueLength] = messageTempPart.Substring(0, messageTempPart.Length - 1);

                // Display the messages
                for (int j = 0; j <= queueLength; j++) {
                    if (queueArray[j].Length > 0) {
                        AddQueue(queueArray[j]);
                    }
                }
                return;
            }

            m_MessageQueue.AddLast(message);
            if (ProfileControl.Global.GetSetting("Automation", "DisableQueue").ToBoolean(false)) {
                SendQueue();
            } else {
                if (m_MessageQueueTimer == null) {
                    // Create the queue timer.
                    m_MessageQueueTimer = new Timer(new TimerCallback((TimerCallbackDelegate) delegate(Object stateInfo) {
                        #region Message Queue Timer
                        SendQueue();
                        #endregion
                    }), null, 0, 1000);
                }
            }
        }

        private void SendQueue() {
            if (m_MessageQueue.Count > 0) {
                if (m_MessageQueueSeconds <= 0) {
                    if (m_MessageQueue.First == null)
                        return;
                    string message = m_MessageQueue.First.Value;
                    if (m_InChat) {
                        m_MessageQueue.RemoveFirst();
                        m_MessageQueueSeconds += ((int) message.Length / 100) + 1;
                        if (m_ChatClient)
                            SendChatPacket(message);
                        else
                            Send_SID_CHATCOMMAND(message);
                        if (message[0] != '/') {
                            m_frmProfile.RichTextBox.AddTextNodes(
                                FCSControl.GetTextNode(FCSObjects.Chatroom_Talk_YourName, m_UniqueUsername),
                                FCSControl.GetTextNode(FCSObjects.Chatroom_Talk_NormalText, message));
                        }
                    } else {
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, "Unable to send text. You're not in chat."));
                        m_frmProfile.RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Talk_NormalText, message));
                        ClearQueue();
                    }
                } else {
                    m_MessageQueueSeconds--;
                }
            } else {
                m_MessageQueueSeconds = 0;
            }
        }

        /// <summary>Clears the queue of messages.</summary>
        public void ClearQueue() {
            m_MessageQueue.Clear();
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the BattleNetClient object which has hash, verbyte,
        /// and name information on the client currently logged in as.
        /// </summary>
        public BattleNetClient Client {
            get { return m_Client; }
        }

        /// <summary>
        /// Gets the unique username, with #s.
        /// </summary>
        public string UniqueUsername {
            get { return m_UniqueUsername; }
        }

        /// <summary>
        /// The username used to log in, without #s.
        /// </summary>
        public string LogonUsername {
            get { return m_Username; }
        }

        /// <summary>
        /// The namespace of the bot.
        /// </summary>
        public string Namespace {
            get { return m_Namespace; }
        }

        /// <summary>
        /// Whether the bot is in chat.
        /// </summary>
        public bool InChat {
            get { return m_InChat; }
        }

        /// <summary>
        /// The realm of the bot.
        /// </summary>
        public string Realm {
            get { return m_Realm; }
        }

        /// <summary>
        /// The user last whispered to.
        /// </summary>
        public string LastWhisperSent {
            get { return m_LastWhisperSent; }
        }

        /// <summary>
        /// The user who last whispered the bot.
        /// </summary>
        public string LastWhisperRecieved {
            get { return m_LastWhisperRecieved; }
        }
        #endregion
    }

    /// <summary>
    /// This class represents the client the bot is connected as.
    /// It contains all of the verbyte, hash paths, and names that
    /// the BattleNetPacketThread uses throughout connection.
    /// This should probably be phased out and put inside the BattleNetPacketThread as well...
    /// </summary>
    public class BattleNetClient {
        #region Fields
        private string m_ProductID;
        private string m_ProductName;
        private string m_HashPath;
        private string[] m_Hashes;
        private string m_ImageFile;
        private byte m_Verbyte;
        #endregion

        #region Properties
        /// <summary>Gets the four-character product ID.</summary>
        public string ProductID {
            get {
                return m_ProductID;
            }
        }

        /// <summary>Gets the full product name.</summary>
        public string ProductName {
            get {
                return m_ProductName;
            }
        }

        /// <summary>Gets the path to this client's hash folder.</summary>
        public string HashPath {
            get {
                return m_HashPath;
            }
        }

        /// <summary>Gets the paths to the three hash files for this client if availbable.</summary>
        public string[] HashFiles {
            get {
                return m_Hashes;
            }
        }
        /// <summary>Gets the path to the image file for this client if available.</summary>
        public string ImageFile {
            get {
                return m_ImageFile;
            }
        }

        /// <summary>Gets the client's verbyte.</summary>
        public byte Verbyte {
            get {
                return m_Verbyte;
            }
        }
        #endregion

        #region Constructors
        private BattleNetClient(string productId) : this(productId, null) { }

        /// <summary>
        /// Create a new BattleNetClient.
        /// </summary>
        /// <param name="a_sProduct">The four-character product ID.</param>
        /// <param name="a_pProfile">The profile that is connecting through this.</param>
        public BattleNetClient(string productId, Profile profile) {
            switch (productId) {
                case "DSHR": m_ProductName = "Diablo: Shareware"; break;
                case "DRTL": m_ProductName = "Diablo"; break;
                case "SSHR": m_ProductName = "StarCraft: Shareware"; break;
                case "JSTR": m_ProductName = "StarCraft: Japan"; break;
                case "STAR": m_ProductName = "StarCraft"; break;
                case "SEXP": m_ProductName = "StarCraft: Brood War"; break;
                case "D2DV": m_ProductName = "Diablo II"; break;
                case "D2XP": m_ProductName = "Diablo II: Lord of Destruction"; break;
                case "W2BN": m_ProductName = "WarCraft II: Battle.net Edition"; break;
                case "WAR3": m_ProductName = "WarCraft III"; break;
                case "W3XP": m_ProductName = "WarCraft III: The Frozen Throne"; break;
                case "CHAT": m_ProductName = "Chat Client"; break;
                default: throw new ArgumentException("Invalid product ID or name.", "productId");
            }
            if (profile == null)
                return;

            string path = Program.ApplicationFolder + profile.GetSetting("AdvConn", "Hashes").ToString("\\Hashes\\");

            m_ProductID = productId;
            switch (productId) {
                case "DSHR":
                    m_HashPath = path + "DSHR\\";
                    m_Hashes = new string[] { HashPath + "Diablo.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "DSHR.bin";
                    m_Verbyte = 0x2A;
                    break;
                case "DRTL":
                    m_HashPath = path + "DRTL\\";
                    m_Hashes = new string[] { HashPath + "Diablo.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "DRTL.bin";
                    m_Verbyte = 0x2A;
                    break;
                case "SSHR":
                    m_HashPath = path + "SSHR\\";
                    m_Hashes = new string[] { HashPath + "StarCraft.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "SSHR.bin";
                    m_Verbyte = 0xA5;
                    break;
                case "JSTR":
                    m_HashPath = path + "JSTR\\";
                    m_Hashes = new string[] { HashPath + "StarCraft.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "JSTR.bin";
                    m_Verbyte = 0xA9;
                    break;
                case "STAR":
                    m_HashPath = path + "STAR\\";
                    m_Hashes = new string[] { HashPath + "StarCraft.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "STAR.bin";
                    m_Verbyte = 0xD1;
                    break;
                case "SEXP":
                    m_HashPath = path + "STAR\\";
                    m_Hashes = new string[] { HashPath + "StarCraft.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "STAR.bin";
                    m_Verbyte = 0xD1;
                    break;
                case "D2DV":
                    m_HashPath = path + "D2DV\\";
                    m_Hashes = new string[] { HashPath + "Game.exe", HashPath + "Bnclient.dll", HashPath + "D2Client.dll" };
                    m_Verbyte = 0x0C;
                    break;
                case "D2XP":
                    m_HashPath = path + "D2DV\\";
                    m_Hashes = new string[] { HashPath + "Game.exe", HashPath + "Bnclient.dll", HashPath + "D2Client.dll" };
                    m_Verbyte = 0x0C;
                    break;
                case "W2BN":
                    m_HashPath = path + "W2BN\\";
                    m_Hashes = new string[] { HashPath + "WarCraft II BNE.exe", HashPath + "storm.dll", HashPath + "battle.snp" };
                    m_ImageFile = HashPath + "W2BN.bin";
                    m_Verbyte = 0x4F;
                    break;
                case "WAR3":
                    m_HashPath = path + "WAR3\\";
                    m_Hashes = new string[] { HashPath + "War3.exe", HashPath + "Storm.dll", HashPath + "Game.dll" };
                    m_Verbyte = 0x16;
                    break;
                case "W3XP":
                    m_HashPath = path + "WAR3\\";
                    m_Hashes = new string[] { HashPath + "War3.exe", HashPath + "Storm.dll", HashPath + "Game.dll" };
                    m_Verbyte = 0x16;
                    break;
                default:
                case "CHAT":
                    break;
            }
            byte verbyte;
            verbyte = (byte) profile.GetSetting("AdvConn", "Verbyte").ToInteger(0xFF);
            if (verbyte != 0xFF)
                m_Verbyte = verbyte;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Determines if this client's product is equal to the one provided.
        /// </summary>
        /// <param name="a">This is the client we are checking.</param>
        /// <returns>Returns true if it is equal.</returns>
        public bool Equals(string a) {
            return (this.ProductID.Equals(a));
        }

        /// <summary>
        /// Gets the full product name for the product ID provided.
        /// </summary>
        /// <param name="product"></param>
        /// <returns></returns>
        public static string GetProductName(string product) {
            return new BattleNetClient(product).ProductName;
        }
        #endregion
    }

    /// <summary>
    /// Specifies the type of client that is connecting to Battle.net.
    /// </summary>
    public enum BattleNetProtocolBytes : byte {
        /// <summary>The protocol byte for the game clients.</summary>
        Game = 0x01,
        /// <summary>The protocol byte for the BNFTP client.</summary>
        Bnftp = 0x02,
        /// <summary>The protocol byte for the CHAT client.</summary>
        Chat = 0x03
    }
}
